push2: master button now does something useful
[ardour.git] / libs / surfaces / push2 / buttons.cc
index 6925517f68247bd3e4006c55eabf23d2403b2a49..035d7b2e5f0eca16f0e4f2d1ccfd09fc066bf8f0 100644 (file)
@@ -23,7 +23,9 @@
 #include "ardour/session.h"
 #include "ardour/solo_control.h"
 
+#include "layout.h"
 #include "push2.h"
+#include "track_mix.h"
 
 using namespace ArdourSurface;
 using namespace ARDOUR;
@@ -39,8 +41,7 @@ Push2::build_maps ()
 
 #define MAKE_PAD(x,y,nn) \
        pad = new Pad ((x), (y), (nn)); \
-       nn_pad_map.insert (std::make_pair (pad->extra(), pad)); \
-       coord_pad_map.insert (std::make_pair (pad->coord(), pad));
+       nn_pad_map.insert (std::make_pair (pad->extra(), pad));
 
        MAKE_PAD (0, 0, 92);
        MAKE_PAD (0, 1, 93);
@@ -119,6 +120,10 @@ Push2::build_maps ()
        button = new ColorButton ((i), (cc), (p)); \
        cc_button_map.insert (std::make_pair (button->controller_number(), button)); \
        id_button_map.insert (std::make_pair (button->id, button))
+#define MAKE_COLOR_BUTTON_PRESS_RELEASE_LONG(i,cc,p,r,l)                      \
+       button = new ColorButton ((i), (cc), (p), (r), (l)); \
+       cc_button_map.insert (std::make_pair (button->controller_number(), button)); \
+       id_button_map.insert (std::make_pair (button->id, button))
 
        MAKE_COLOR_BUTTON_PRESS (Upper1, 102, &Push2::button_upper_1);
        MAKE_COLOR_BUTTON_PRESS (Upper2, 103, &Push2::button_upper_2);
@@ -136,9 +141,9 @@ Push2::build_maps ()
        MAKE_COLOR_BUTTON_PRESS (Lower6, 25, &Push2::button_lower_6);
        MAKE_COLOR_BUTTON_PRESS (Lower7, 26, &Push2::button_lower_7);
        MAKE_COLOR_BUTTON_PRESS (Lower8, 27, &Push2::button_lower_8);
-       MAKE_COLOR_BUTTON (Master, 28);
-       MAKE_COLOR_BUTTON (Mute, 60);
-       MAKE_COLOR_BUTTON_PRESS (Solo, 61, &Push2::button_solo);
+       MAKE_COLOR_BUTTON_PRESS (Master, 28, &Push2::button_master);
+       MAKE_COLOR_BUTTON_PRESS (Mute, 60, &Push2::button_mute);
+       MAKE_COLOR_BUTTON_PRESS_RELEASE_LONG (Solo, 61, &Push2::relax, &Push2::button_solo, &Push2::button_solo_long_press);
        MAKE_COLOR_BUTTON_PRESS (Stop, 29, &Push2::button_stop);
        MAKE_COLOR_BUTTON_PRESS (Fwd32ndT, 43, &Push2::button_fwd32t);
        MAKE_COLOR_BUTTON_PRESS (Fwd32nd,42 , &Push2::button_fwd32);
@@ -176,7 +181,7 @@ Push2::build_maps ()
        MAKE_WHITE_BUTTON (Delete, 118);
        MAKE_WHITE_BUTTON (AddDevice, 52);
        MAKE_WHITE_BUTTON (Device, 110);
-       MAKE_WHITE_BUTTON (Mix, 112);
+       MAKE_WHITE_BUTTON_PRESS (Mix, 112, &Push2::button_mix_press);
        MAKE_WHITE_BUTTON_PRESS (Undo, 119, &Push2::button_undo);
        MAKE_WHITE_BUTTON_PRESS (AddTrack, 53, &Push2::button_add_track);
        MAKE_WHITE_BUTTON_PRESS (Browse, 111, &Push2::button_browse);
@@ -193,7 +198,7 @@ Push2::build_maps ()
        MAKE_WHITE_BUTTON_PRESS (Left, 44, &Push2::button_left);
        MAKE_WHITE_BUTTON_PRESS (Repeat, 56, &Push2::button_repeat);
        MAKE_WHITE_BUTTON (Accent, 57);
-       MAKE_WHITE_BUTTON (Scale, 58);
+       MAKE_WHITE_BUTTON_PRESS (Scale, 58, &Push2::button_scale_press);
        MAKE_WHITE_BUTTON_PRESS (Layout, 31, &Push2::button_layout_press);
        MAKE_WHITE_BUTTON (Note, 50);
        MAKE_WHITE_BUTTON (Session, 51);
@@ -213,7 +218,7 @@ Push2::button_play ()
                return;
        }
 
-       if (modifier_state & ModShift) {
+       if (_modifier_state & ModShift) {
                goto_start (session->transport_rolling());
                return;
        }
@@ -234,13 +239,13 @@ Push2::button_recenable ()
 void
 Push2::button_up ()
 {
-       scroll_up_1_track ();
+       _current_layout->button_up ();
 }
 
 void
 Push2::button_down ()
 {
-       scroll_dn_1_track ();
+       _current_layout->button_down ();
 }
 
 void
@@ -258,13 +263,13 @@ Push2::button_page_left ()
 void
 Push2::button_right ()
 {
-       switch_bank (max (0, bank_start + 8));
+       _current_layout->button_right ();
 }
 
 void
 Push2::button_left ()
 {
-       switch_bank (max (0, bank_start - 8));
+       _current_layout->button_left ();
 }
 
 void
@@ -280,11 +285,27 @@ Push2::button_metronome ()
 }
 
 void
-Push2::button_solo ()
+Push2::button_solo_long_press ()
 {
        cancel_all_solo ();
 }
 
+void
+Push2::button_mute ()
+{
+       if (_current_layout) {
+               _current_layout->button_mute ();
+       }
+}
+
+void
+Push2::button_solo ()
+{
+       if (_current_layout) {
+               _current_layout->button_solo ();
+       }
+}
+
 void
 Push2::button_new ()
 {
@@ -331,45 +352,19 @@ Push2::button_clip ()
 void
 Push2::button_upper (uint32_t n)
 {
-       if (!stripable[n]) {
-               return;
-       }
-
-       if (modifier_state & ModShift) {
-               boost::shared_ptr<AutomationControl> sc = stripable[n]->rec_enable_control ();
-               if (sc) {
-                       sc->set_value (!sc->get_value(), PBD::Controllable::UseGroup);
-               }
-       } else {
-               boost::shared_ptr<SoloControl> sc = stripable[n]->solo_control ();
-               if (sc) {
-                       sc->set_value (!sc->self_soloed(), PBD::Controllable::UseGroup);
-               }
-       }
+       _current_layout->button_upper (n);
 }
 
 void
 Push2::button_lower (uint32_t n)
 {
-       if (!stripable[n]) {
-               return;
-       }
-
-       if (modifier_state & ModSelect) {
-               SetStripableSelection (stripable[n]);
-       } else {
-               boost::shared_ptr<MuteControl> mc = stripable[n]->mute_control ();
-
-               if (mc) {
-                       mc->set_value (!mc->muted_by_self(), PBD::Controllable::UseGroup);
-               }
-       }
+       _current_layout->button_lower (n);
 }
 
 void
 Push2::button_undo ()
 {
-       if (modifier_state & ModShift) {
+       if (_modifier_state & ModShift) {
                ControlProtocol::Redo ();
        } else {
                ControlProtocol::Undo ();
@@ -379,56 +374,56 @@ Push2::button_undo ()
 void
 Push2::button_fwd32t ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (0+n);
 }
 
 void
 Push2::button_fwd32 ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (1+n);
 }
 
 void
 Push2::button_fwd16t ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (2+n);
 }
 
 void
 Push2::button_fwd16 ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (3+n);
 }
 
 void
 Push2::button_fwd8t ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (4+n);
 }
 
 void
 Push2::button_fwd8 ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (5+n);
 }
 
 void
 Push2::button_fwd4t ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (6+n);
 }
 
 void
 Push2::button_fwd4 ()
 {
-       const int n = (modifier_state & ModShift) ? 8 : 0;
+       const int n = (_modifier_state & ModShift) ? 8 : 0;
        goto_nth_marker (7+n);
 }
 
@@ -466,93 +461,30 @@ Push2::button_shift_long_press ()
 void
 Push2::button_select_press ()
 {
-       start_select ();
+       cerr << "start select\n";
+       _modifier_state = ModifierState (_modifier_state | ModSelect);
+       Button* b = id_button_map[Select];
+       b->set_color (Push2::LED::White);
+       b->set_state (Push2::LED::Blinking16th);
+       write (b->state_msg());
+
+       _current_layout->button_select_press ();
 }
 
 void
 Push2::button_select_release ()
 {
-       if (!(modifier_state & ModSelect)) {
-               /* somebody else used us as a modifier */
-               return;
+       if (_modifier_state & ModSelect) {
+               cerr << "end select\n";
+               _modifier_state = ModifierState (_modifier_state & ~(ModSelect));
+               Button* b = id_button_map[Select];
+               b->timeout_connection.disconnect ();
+               b->set_color (Push2::LED::White);
+               b->set_state (Push2::LED::OneShot24th);
+               write (b->state_msg());
        }
 
-       end_select ();
-
-       int selected = -1;
-
-       for (int n = 0; n < 8; ++n) {
-               if (stripable[n]) {
-                       if (stripable[n]->presentation_info().selected()) {
-                                       selected = n;
-                                       break;
-                       }
-               }
-       }
-
-       if (selected < 0) {
-
-               /* no visible track selected, select first (if any) */
-
-               if (stripable[0]) {
-                       SetStripableSelection (stripable[0]);
-               }
-
-       } else {
-
-               if (modifier_state & ModShift) {
-                       std::cerr << "select prev\n";
-                       /* select prev */
-
-                       if (selected == 0) {
-                               /* current selected is leftmost ... cancel selection,
-                                  switch banks by one, and select leftmost
-                               */
-                               if (bank_start != 0) {
-                                       ClearStripableSelection ();
-                                       switch_bank (bank_start-1);
-                                       if (stripable[0]) {
-                                               SetStripableSelection (stripable[0]);
-                                       }
-                               }
-                       } else {
-                               /* select prev, if any */
-                               int n = selected - 1;
-                               while (n >= 0 && !stripable[n]) {
-                                       --n;
-                               }
-                               if (n >= 0) {
-                                       SetStripableSelection (stripable[n]);
-                               }
-                       }
-
-               } else {
-
-                       std::cerr << "select next\n";
-                       /* select next */
-
-                       if (selected == 7) {
-                               /* current selected is rightmost ... cancel selection,
-                                  switch banks by one, and select righmost
-                               */
-                               ToggleStripableSelection (stripable[selected]);
-                               switch_bank (bank_start+1);
-                               if (stripable[7]) {
-                                       SetStripableSelection (stripable[7]);
-                               }
-                       } else {
-                               /* select next, if any */
-                               int n = selected + 1;
-                               while (n < 8 && !stripable[n]) {
-                                       ++n;
-                               }
-
-                               if (n != 8) {
-                                       SetStripableSelection (stripable[n]);
-                               }
-                       }
-               }
-       }
+       _current_layout->button_select_release ();
 }
 
 void
@@ -592,19 +524,218 @@ Push2::start_press_timeout (Button& button, ButtonID id)
 void
 Push2::button_octave_down ()
 {
+       if (_modifier_state & ModShift) {
+               octave_shift = 0;
+               return;
+       }
+
        int os = (max (-4, octave_shift - 1));
        if (os != octave_shift) {
                octave_shift = os;
-               build_pad_table ();
        }
 }
 
 void
 Push2::button_octave_up ()
 {
+       if (_modifier_state & ModShift) {
+               octave_shift = 0;
+               return;
+       }
+
        int os = (min (4, octave_shift + 1));
        if (os != octave_shift) {
                octave_shift = os;
-               build_pad_table ();
        }
 }
+
+void
+Push2::button_layout_press ()
+{
+       if (percussion) {
+               set_percussive_mode (false);
+       } else {
+               set_percussive_mode (true);
+       }
+}
+
+void
+Push2::button_scale_press ()
+{
+       if (_current_layout != scale_layout) {
+               set_current_layout (scale_layout);
+       } else {
+               if (ControlProtocol::first_selected_stripable()) {
+                       set_current_layout (mix_layout);
+               }
+       }
+}
+
+void
+Push2::button_mix_press ()
+{
+       if (_current_layout == track_mix_layout) {
+               set_current_layout (mix_layout);
+       } else {
+               if (ControlProtocol::first_selected_stripable()) {
+                       set_current_layout (track_mix_layout);
+               }
+       }
+}
+
+void
+Push2::button_master ()
+{
+       boost::shared_ptr<Stripable> master = session->master_out();
+
+       if (!master) {
+               return;
+       }
+
+       ControlProtocol::SetStripableSelection (master);
+
+       if (_current_layout != track_mix_layout) {
+               set_current_layout (track_mix_layout);
+       }
+}
+
+std::string
+Push2::button_name_by_id (ButtonID id)
+{
+       switch (id) {
+       case TapTempo:
+               return "TapTempo";
+       case Metronome:
+               return "Metronome";
+       case Upper1:
+               return "Upper1";
+       case Upper2:
+               return "Upper2";
+       case Upper3:
+               return "Upper3";
+       case Upper4:
+               return "Upper4";
+       case Upper5:
+               return "Upper5";
+       case Upper6:
+               return "Upper6";
+       case Upper7:
+               return "Upper7";
+       case Upper8:
+               return "Upper8";
+       case Setup:
+               return "Setup";
+       case User:
+               return "User";
+       case Delete:
+               return "Delete";
+       case AddDevice:
+               return "AddDevice";
+       case Device:
+               return "Device";
+       case Mix:
+               return "Mix";
+       case Undo:
+               return "Undo";
+       case AddTrack:
+               return "AddTrack";
+       case Browse:
+               return "Browse";
+       case Clip:
+               return "Clip";
+       case Mute:
+               return "Mute";
+       case Solo:
+               return "Solo";
+       case Stop:
+               return "Stop";
+       case Lower1:
+               return "Lower1";
+       case Lower2:
+               return "Lower2";
+       case Lower3:
+               return "Lower3";
+       case Lower4:
+               return "Lower4";
+       case Lower5:
+               return "Lower5";
+       case Lower6:
+               return "Lower6";
+       case Lower7:
+               return "Lower7";
+       case Lower8:
+               return "Lower8";
+       case Master:
+               return "Master";
+       case Convert:
+               return "Convert";
+       case DoubleLoop:
+               return "DoubleLoop";
+       case Quantize:
+               return "Quantize";
+       case Duplicate:
+               return "Duplicate";
+       case New:
+               return "New";
+       case FixedLength:
+               return "FixedLength";
+       case Automate:
+               return "Automate";
+       case RecordEnable:
+               return "RecordEnable";
+       case Play:
+               return "Play";
+       case Fwd32ndT:
+               return "Fwd32ndT";
+       case Fwd32nd:
+               return "Fwd32nd";
+       case Fwd16thT:
+               return "Fwd16thT";
+       case Fwd16th:
+               return "Fwd16th";
+       case Fwd8thT:
+               return "Fwd8thT";
+       case Fwd8th:
+               return "Fwd8th";
+       case Fwd4trT:
+               return "Fwd4trT";
+       case Fwd4tr:
+               return "Fwd4tr";
+       case Up:
+               return "Up";
+       case Right:
+               return "Right";
+       case Down:
+               return "Down";
+       case Left:
+               return "Left";
+       case Repeat:
+               return "Repeat";
+       case Accent:
+               return "Accent";
+       case Scale:
+               return "Scale";
+       case Layout:
+               return "Layout";
+       case Note:
+               return "Note";
+       case Session:
+               return "Session";
+       case OctaveUp:
+               return "OctaveUp";
+       case PageRight:
+               return "PageRight";
+       case OctaveDown:
+               return "OctaveDown";
+       case PageLeft:
+               return "PageLeft";
+       case Shift:
+               return "Shift";
+       case Select:
+               return "Select";
+       default:
+               break;
+       }
+
+       return "???";
+}