From b98ec59ed814a8c634dfcfa7aa1667ef19b6afda Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 28 Aug 2022 18:58:50 -0600 Subject: [PATCH] push2: another bunch of Live-chasing functionality for trigger control --- libs/surfaces/push2/cues.cc | 229 ++++++++++++++++++++++++++++++----- libs/surfaces/push2/cues.h | 12 +- libs/surfaces/push2/push2.cc | 36 ++++++ libs/surfaces/push2/push2.h | 1 + 4 files changed, 244 insertions(+), 34 deletions(-) diff --git a/libs/surfaces/push2/cues.cc b/libs/surfaces/push2/cues.cc index ec039815ba..02c70348f3 100644 --- a/libs/surfaces/push2/cues.cc +++ b/libs/surfaces/push2/cues.cc @@ -87,6 +87,7 @@ CueLayout::CueLayout (Push2& p, Session & s, std::string const & name) , track_base (0) , scene_base (0) , _knob_function (KnobGain) + , _long_stop (0) { Pango::FontDescription fd ("Sans 10"); @@ -261,7 +262,7 @@ CueLayout::show_knob_function () void CueLayout::button_lower (uint32_t n) { - if (_p2.stop_down()) { + if (_p2.stop_down() || _long_stop) { std::cerr << "stop trigger in " << n + track_base << std::endl; _p2.unbang (n + track_base); } else { @@ -351,40 +352,17 @@ CueLayout::viewport_changed () { _route_connections.drop_connections (); + for (int n = 0; n < 64; ++n) { + _trig_connections[n].disconnect (); + } + for (int n = 0; n < 8; ++n) { _route[n] = _session.get_remote_nth_route (track_base+n); boost::shared_ptr r = _route[n]; - boost::shared_ptr lower_button; - - switch (n) { - case 0: - lower_button = _p2.button_by_id (Push2::Lower1); - break; - case 1: - lower_button = _p2.button_by_id (Push2::Lower2); - break; - case 2: - lower_button = _p2.button_by_id (Push2::Lower3); - break; - case 3: - lower_button = _p2.button_by_id (Push2::Lower4); - break; - case 4: - lower_button = _p2.button_by_id (Push2::Lower5); - break; - case 5: - lower_button = _p2.button_by_id (Push2::Lower6); - break; - case 6: - lower_button = _p2.button_by_id (Push2::Lower7); - break; - case 7: - lower_button = _p2.button_by_id (Push2::Lower8); - break; - } + boost::shared_ptr lower_button = _p2.lower_button_by_column (n); if (r) { _route[n]->DropReferences.connect (_route_connections, invalidator (*this), boost::bind (&CueLayout::viewport_changed, this), &_p2); @@ -447,6 +425,9 @@ CueLayout::viewport_changed () if (tp && tp->region()) { /* trigger in slot */ pad->set_color (color); + + tp->PropertyChanged.connect (_trig_connections[n * 8 + y], invalidator (*this), boost::bind (&CueLayout::trigger_property_change, this, _1, n, y), &_p2); + } else { /* no trigger */ pad->set_color (Push2::LED::Black); @@ -514,12 +495,95 @@ CueLayout::button_stop_press () _p2.get_session().stop_all_triggers (false); /* quantized global stop */ } } +void +CueLayout::button_stop_release () +{ + std::cerr << "BS release, ls = " << _long_stop << std::endl; + if (_long_stop) { + _long_stop = 0; + show_running_boxen (false); + } +} void -CueLayout::pad_press (int x, int y) +CueLayout::button_stop_long_press () +{ + _long_stop++; + + if (_long_stop == 1) { + show_running_boxen (true); + } +} + +void +CueLayout::show_running_boxen (bool yn) +{ + Push2::ButtonID lower_buttons[] = { + Push2::Lower1, Push2::Lower2, Push2::Lower3, Push2::Lower4, + Push2::Lower5, Push2::Lower6, Push2::Lower7, Push2::Lower8 + }; + + for (int n = 0; n < 8; ++n) { + boost::shared_ptr lower_button = _p2.button_by_id (lower_buttons[n]); + + if (!_route[n]) { + continue; + } + + boost::shared_ptr tb = _route[n]->triggerbox(); + assert (tb); + + if (yn) { + + if (!tb->currently_playing()) { + /* nothing playing, do not turn the blink on */ + continue; + } + + HSV hsv (_route[n]->presentation_info().color()); + hsv = hsv.shade (2.0); + lower_button->set_color (_p2.get_color_index (hsv.color())); + lower_button->set_state (Push2::LED::Blinking4th); + + } else { + std::cerr << "no blink " << n << std::endl; + lower_button->set_color (_p2.get_color_index (_route[n]->presentation_info().color())); + lower_button->set_state (Push2::LED::NoTransition); + } + + _p2.write (lower_button->state_msg()); + } +} + +void +CueLayout::pad_press (int y, int x) /* fix coordinate order one day */ { std::cerr << "bang on " << x + track_base << ", " << y + scene_base << std::endl; - _p2.bang (y + scene_base, x + track_base); + + if (!_route[x]) { + std::cerr << "no route\n"; + return; + } + + boost::shared_ptr tb = _route[x]->triggerbox(); + + if (!tb) { + std::cerr << "no TB\n"; + /* unpossible! */ + return; + } + + if (!tb->trigger (y + scene_base)->region()) { + std::cerr << "empty slot, unbang TB\n"; + _p2.unbang (x + track_base); + return; + } + + std::cerr << "bang TB\n"; + _p2.bang (x + track_base, y + scene_base); + + + } void @@ -587,8 +651,109 @@ CueLayout::route_property_change (PropertyChange const& what_changed, uint32_t w } +void +CueLayout::trigger_property_change (PropertyChange const& what_changed, uint32_t col, uint32_t row) +{ + assert (_route[col]); + + if (what_changed.contains (Properties::running)) { + boost::shared_ptr tb = _route[col]->triggerbox (); + assert (tb); + + TriggerPtr trig = tb->trigger (row); + assert (trig); + + boost::shared_ptr pad = _p2.pad_by_xy (col, row); + assert (pad); + + set_pad_color_from_trigger_state (col, pad, trig); + _p2.write (pad->state_msg()); + } +} void -CueLayout::triggerbox_property_change (PropertyChange const& what_changed, uint32_t which) +CueLayout::triggerbox_property_change (PropertyChange const& what_changed, uint32_t col) { + std::cerr << "TB prop change "; what_changed.dump (std::cerr); std::cerr << std::endl; + + assert (_route[col]); + + if (what_changed.contains (Properties::currently_playing) || what_changed.contains (Properties::queued)) { + + boost::shared_ptr tb = _route[col]->triggerbox (); + assert (tb); + + + /* make sure the blink state of all 8 pads for this + * route/triggerbox are correct + */ + + for (uint32_t y = 0; y < 8; ++y) { + boost::shared_ptr pad = _p2.pad_by_xy (col, y); + assert (pad); + + TriggerPtr trig = tb->trigger (y); + assert (trig); + + set_pad_color_from_trigger_state (col, pad, trig); + + _p2.write (pad->state_msg()); + } + + + if (!what_changed.contains (Properties::queued)) { + + /* currently_playing changed, if nothing is playing be + * sure to disable blink on lower button + */ + + std::cerr << "running change on " << col << std::endl; + + if (!tb->currently_playing()) { + boost::shared_ptr lower_button = _p2.lower_button_by_column (col); + lower_button->set_color (_p2.get_color_index (_route[col]->presentation_info().color())); + lower_button->set_state (Push2::LED::NoTransition); + _p2.write (lower_button->state_msg()); + } + } + } +} + +void +CueLayout::set_pad_color_from_trigger_state (int col, boost::shared_ptr pad, TriggerPtr trig) +{ + if (trig->region()) { + + if (trig->active()) { + + /* running or waiting to stop */ + + HSV hsv (_route[col]->presentation_info().color()); + hsv = hsv.shade (2.0); + pad->set_color (_p2.get_color_index (hsv.color ())); + pad->set_state (Push2::LED::Pulsing4th); + + } else if (trig == trig->box().peek_next_trigger()) { + + /* waiting to start */ + + HSV hsv (_route[col]->presentation_info().color()); + hsv = hsv.shade (2.0); + pad->set_color (_p2.get_color_index (hsv.color ())); + pad->set_state (Push2::LED::Pulsing16th); + + } else { + + /* not running */ + + pad->set_color (_p2.get_color_index (_route[col]->presentation_info().color())); + pad->set_state (Push2::LED::NoTransition); + } + + } else { + + /* empty slot */ + pad->set_color (Push2::LED::Black); + pad->set_state (Push2::LED::NoTransition); + } } diff --git a/libs/surfaces/push2/cues.h b/libs/surfaces/push2/cues.h index f237bcd1ef..39063ba13e 100644 --- a/libs/surfaces/push2/cues.h +++ b/libs/surfaces/push2/cues.h @@ -22,6 +22,7 @@ #include #include "layout.h" +#include "push2.h" namespace ARDOUR { class Route; @@ -72,6 +73,8 @@ class CueLayout : public Push2Layout void button_page_left(); void button_page_right(); void button_stop_press (); + void button_stop_release (); + void button_stop_long_press (); void strip_vpot (int, int); void strip_vpot_touch (int, bool); @@ -91,14 +94,17 @@ class CueLayout : public Push2Layout uint32_t track_base; uint32_t scene_base; KnobFunction _knob_function; + int _long_stop; - PBD::ScopedConnectionList _route_connections; + PBD::ScopedConnectionList _route_connections; boost::shared_ptr _route[8]; - PBD::ScopedConnectionList _session_connections; + PBD::ScopedConnectionList _session_connections; + PBD::ScopedConnection _trig_connections[64]; void routes_added (); void route_property_change (PBD::PropertyChange const& what_changed, uint32_t which); void triggerbox_property_change (PBD::PropertyChange const& what_changed, uint32_t which); + void trigger_property_change (PBD::PropertyChange const& what_changed, uint32_t col, uint32_t row); ArdourCanvas::Arc* _progress[8]; boost::shared_ptr _controllables[8]; @@ -108,6 +114,8 @@ class CueLayout : public Push2Layout void show_state (); void update_clip_progress (int); void show_knob_function (); + void set_pad_color_from_trigger_state (int col, boost::shared_ptr, boost::shared_ptr); + void show_running_boxen (bool); }; } /* namespace */ diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index 1f9de05c77..4fa953f6b2 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -1912,3 +1912,39 @@ Push2::pad_by_xy (int x, int y) } return _xy_pad_map[index]; } + +boost::shared_ptr +Push2::lower_button_by_column (uint32_t col) +{ + assert (col < 8); + + switch (col) { + case 0: + return button_by_id (Push2::Lower1); + break; + case 1: + return button_by_id (Push2::Lower2); + break; + case 2: + return button_by_id (Push2::Lower3); + break; + case 3: + return button_by_id (Push2::Lower4); + break; + case 4: + return button_by_id (Push2::Lower5); + break; + case 5: + return button_by_id (Push2::Lower6); + break; + case 6: + return button_by_id (Push2::Lower7); + break; + case 7: + return button_by_id (Push2::Lower8); + break; + } + /*NOTREACHED*/ + return boost::shared_ptr(); +} + diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index f2467e909d..689baa9b48 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -457,6 +457,7 @@ class Push2 : public ARDOUR::ControlProtocol PadMap const & nn_pad_map() const { return _nn_pad_map; } boost::shared_ptr pad_by_xy (int x, int y); + boost::shared_ptr