push2: working bidirectional communication, some transport control/display (LED only...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 16 Jun 2016 18:06:16 +0000 (14:06 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Sep 2016 19:59:29 +0000 (14:59 -0500)
libs/ardour/control_protocol_manager.cc
libs/surfaces/push2/buttons.cc [new file with mode: 0644]
libs/surfaces/push2/leds.cc
libs/surfaces/push2/push2.cc
libs/surfaces/push2/push2.h
libs/surfaces/push2/wscript

index a0a36c17dd2150480e4262d4caea12dd51a8fa14..b2c91539913211ef369c6a54e8b69e1938565176 100644 (file)
@@ -453,6 +453,8 @@ ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
                                delete cpi->state;
                                cpi->state = new XMLNode (**citer);
 
                                delete cpi->state;
                                cpi->state = new XMLNode (**citer);
 
+                               std::cerr << "protocol " << prop->value() << " active ? " << active << std::endl;
+
                                if (active) {
                                        if (_session) {
                                                instantiate (*cpi);
                                if (active) {
                                        if (_session) {
                                                instantiate (*cpi);
@@ -466,6 +468,8 @@ ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
                                                cpi->requested = false;
                                        }
                                }
                                                cpi->requested = false;
                                        }
                                }
+                       } else {
+                               std::cerr << "protocol " << prop->value() << " not found\n";
                        }
                }
        }
                        }
                }
        }
diff --git a/libs/surfaces/push2/buttons.cc b/libs/surfaces/push2/buttons.cc
new file mode 100644 (file)
index 0000000..1db04f4
--- /dev/null
@@ -0,0 +1,34 @@
+#include "ardour/session.h"
+
+#include "push2.h"
+
+using namespace ArdourSurface;
+
+void
+Push2::button_play ()
+{
+       if (session->transport_rolling ()) {
+               transport_stop ();
+       } else {
+               transport_play ();
+       }
+}
+
+void
+Push2::button_recenable ()
+{
+       std::cerr << "RE toggle\n";
+       rec_enable_toggle ();
+}
+
+void
+Push2::button_up ()
+{
+       scroll_up_1_track ();
+}
+
+void
+Push2::button_down ()
+{
+       scroll_dn_1_track ();
+}
index 1e5423e17abd67648a08ef476a032fa2f37a0ab5..75921f1b49e500520c8322f52d653e7a46f72bea 100644 (file)
@@ -10,141 +10,12 @@ using std::min;
 void
 Push2::LED::set_color (uint8_t ci)
 {
 void
 Push2::LED::set_color (uint8_t ci)
 {
-       color_index = max (uint8_t(0), min (uint8_t(127), ci));
+       _color_index = max (uint8_t(0), min (uint8_t(127), ci));
 }
 
 void
 Push2::LED::set_state (LED::State s)
 {
 }
 
 void
 Push2::LED::set_state (LED::State s)
 {
-       state = s;
+       _state = s;
 }
 
 }
 
-MidiByteArray
-Push2::LED::update ()
-{
-       MidiByteArray msg;
-
-       switch (type) {
-       case Pad:
-       case TouchStrip:
-               msg.push_back (0x90);
-               break;
-       case ColorButton:
-       case WhiteButton:
-               msg.push_back (0xb0);
-               break;
-       }
-
-       msg.push_back (state);
-       msg.push_back (color_index);
-
-       return msg;
-}
-
-void
-Push2::set_led_color (uint32_t id, uint8_t color_index)
-{
-       leds[id].set_color (color_index);
-       // write (leds[id].update ());
-}
-
-void
-Push2::build_led_map ()
-{
-       uint8_t id = 0;
-       uint8_t extra;
-
-       /* Touch strip - there is only one */
-
-       leds.insert (make_pair (id, LED (id, LED::TouchStrip, 12)));
-       id++;
-
-       /* Pads
-
-          Pad 0 is in the bottom left corner, id rises going left=>right
-          across each row
-       */
-
-       for (extra = 36; id < 64; ++id, ++extra) {
-               leds.insert (make_pair (id, LED (id, LED::Pad, extra)));
-       }
-
-       /* Buttons
-
-          We start with Button 0 at the upper left of the surface, increasing
-          across the device and wrapping, until we're at the Master button on
-          the right.
-
-          Then we descend down the left side. Then down the right side of the
-          pads. Finally the column on the far right., going clockwise around
-          each 4-way diagonal button.
-
-          66 buttons in total
-       */
-
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 3)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 9)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 102)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 103)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 104)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 105)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 106)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 107)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 108)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 109)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 30)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 59)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 118)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 52)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 110)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 112)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 119)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 53)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 111)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 113)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 60)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 61)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 29)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 20)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 21)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 22)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 23)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 24)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 25)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 26)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 27)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 28)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 35)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 117)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 116)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 88)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 87)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 90)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 89)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 86)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 85)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 43)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 42)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 41)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 40)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 39)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 38)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 37)));
-       leds.insert (make_pair (id, LED (id, LED::ColorButton, 36)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 46)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 45)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 47)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 44)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 56)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 57)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 58)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 31)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 50)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 51)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 55)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 63)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 54)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 62)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 49)));
-       leds.insert (make_pair (id, LED (id, LED::WhiteButton, 48)));
-}
index 4920a18e5e154f2fc74765a7363235ccd62fb8b9..9b6d84dbe3a5510c1bc5641597a7f61956cb0fef 100644 (file)
@@ -24,6 +24,8 @@
 #include "pbd/debug.h"
 #include "pbd/failed_constructor.h"
 
 #include "pbd/debug.h"
 #include "pbd/failed_constructor.h"
 
+#include "midi++/parser.h"
+
 #include "ardour/async_midi_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/debug.h"
 #include "ardour/async_midi_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/debug.h"
@@ -48,14 +50,14 @@ const int Push2::pixels_per_row = 1024;
 #define ABLETON 0x2982
 #define PUSH2   0x1967
 
 #define ABLETON 0x2982
 #define PUSH2   0x1967
 
-Push2::Push2 (Session& s)
-       : ControlProtocol (s, string (X_("Ableton Push2")))
+Push2::Push2 (ARDOUR::Session& s)
+       : ControlProtocol (s, string (X_("Ableton Push 2")))
        , AbstractUI<Push2Request> (name())
        , handle (0)
        , device_buffer (0)
        , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
 {
        , AbstractUI<Push2Request> (name())
        , handle (0)
        , device_buffer (0)
        , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
 {
-       build_led_map ();
+       build_maps ();
 }
 
 Push2::~Push2 ()
 }
 
 Push2::~Push2 ()
@@ -120,6 +122,8 @@ Push2::open ()
        asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port[1]));
        asp->xthread().attach (main_loop()->get_context());
 
        asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port[1]));
        asp->xthread().attach (main_loop()->get_context());
 
+       connect_to_parser ();
+
        return 0;
 }
 
        return 0;
 }
 
@@ -137,6 +141,8 @@ Push2::close ()
        _async_out[1].reset ((ARDOUR::Port*) 0);
 
        vblank_connection.disconnect ();
        _async_out[1].reset ((ARDOUR::Port*) 0);
 
        vblank_connection.disconnect ();
+       periodic_connection.disconnect ();
+       session_connections.drop_connections ();
 
        if (handle) {
                libusb_release_interface (handle, 0x00);
 
        if (handle) {
                libusb_release_interface (handle, 0x00);
@@ -298,7 +304,7 @@ Push2::set_active (bool yn)
                        return -1;
                }
 
                        return -1;
                }
 
-               // connect_session_signals ();
+               connect_session_signals ();
 
                /* say hello */
 
 
                /* say hello */
 
@@ -339,6 +345,11 @@ Push2::set_active (bool yn)
                vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
                vblank_timeout->attach (main_loop()->get_context());
 
                vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
                vblank_timeout->attach (main_loop()->get_context());
 
+
+               Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (1000); // milliseconds
+               periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &Push2::periodic));
+               periodic_timeout->attach (main_loop()->get_context());
+
        } else {
 
                stop ();
        } else {
 
                stop ();
@@ -356,6 +367,7 @@ void
 Push2::write (int port, const MidiByteArray& data)
 {
        /* immediate delivery */
 Push2::write (int port, const MidiByteArray& data)
 {
        /* immediate delivery */
+       cerr << data << endl;
        _output_port[port]->write (&data[0], data.size(), 0);
 }
 
        _output_port[port]->write (&data[0], data.size(), 0);
 }
 
@@ -369,17 +381,373 @@ Push2::midi_input_handler (IOCondition ioc, MIDI::Port* port)
 
        if (ioc & IO_IN) {
 
 
        if (ioc & IO_IN) {
 
-               DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on  %1\n", port->name()));
+               // DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on  %1\n", port->name()));
 
                AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
                if (asp) {
                        asp->clear ();
                }
 
 
                AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
                if (asp) {
                        asp->clear ();
                }
 
-               DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
+               //DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
                framepos_t now = AudioEngine::instance()->sample_time();
                framepos_t now = AudioEngine::instance()->sample_time();
-               // port->parse (now);
+               port->parse (now);
        }
 
        return true;
 }
        }
 
        return true;
 }
+
+bool
+Push2::periodic ()
+{
+       return true;
+}
+
+void
+Push2::connect_to_parser ()
+{
+       DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port[0]->name()));
+
+       MIDI::Parser* p = _input_port[0]->parser();
+
+       /* Incoming sysex */
+       p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3));
+       /* V-Pot messages are Controller */
+       p->controller.connect_same_thread (*this, boost::bind (&Push2::handle_midi_controller_message, this, _1, _2));
+       /* Button messages are NoteOn */
+       p->note_on.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
+       /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
+       p->note_off.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
+       /* Fader messages are Pitchbend */
+       p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Push2::handle_midi_pitchbend_message, this, _1, _2));
+}
+
+void
+Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz)
+{
+       cerr << "sysex, " << sz << " bytes\n";
+}
+
+void
+Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
+{
+       cerr << "controller " << (int) ev->controller_number << " = " << (int) ev->value << endl;
+       CCButtonMap::iterator b = cc_button_map.find (ev->controller_number);
+       if (b != cc_button_map.end()) {
+               if (ev->value == 0) {
+                       (this->*b->second->release_method)();
+               } else {
+                       (this->*b->second->press_method)();
+               }
+       }
+}
+
+void
+Push2::handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
+{
+       cerr << "note on" << (int) ev->note_number << ", velocity " << (int) ev->velocity << endl;
+}
+
+void
+Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
+{
+       cerr << "note on" << (int) ev->note_number << ", velocity " << (int) ev->velocity << endl;
+}
+
+void
+Push2::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb)
+{
+       cerr << "pitchbend @ " << pb << endl;
+}
+
+void
+Push2::build_maps ()
+{
+       /* Pads */
+
+       Pad* pad;
+
+#define MAKE_PAD(x,y,nn) \
+       pad = new Pad ((x), (y), (nn)); \
+       nn_pad_map.insert (make_pair (pad->extra(), pad)); \
+       coord_pad_map.insert (make_pair (pad->coord(), pad));
+
+       MAKE_PAD (0, 1, 93);
+       MAKE_PAD (0, 2, 94);
+       MAKE_PAD (0, 3, 95);
+       MAKE_PAD (0, 4, 96);
+       MAKE_PAD (0, 5, 97);
+       MAKE_PAD (0, 6, 98);
+       MAKE_PAD (0, 7, 90);
+       MAKE_PAD (1, 0, 84);
+       MAKE_PAD (1, 1, 85);
+       MAKE_PAD (1, 2, 86);
+       MAKE_PAD (1, 3, 87);
+       MAKE_PAD (1, 4, 88);
+       MAKE_PAD (1, 5, 89);
+       MAKE_PAD (1, 6, 90);
+       MAKE_PAD (1, 7, 91);
+       MAKE_PAD (2, 0, 76);
+       MAKE_PAD (2, 1, 77);
+       MAKE_PAD (2, 2, 78);
+       MAKE_PAD (2, 3, 79);
+       MAKE_PAD (2, 4, 80);
+       MAKE_PAD (2, 5, 81);
+       MAKE_PAD (2, 6, 82);
+       MAKE_PAD (2, 7, 83);
+       MAKE_PAD (3, 0, 68);
+       MAKE_PAD (3, 1, 69);
+       MAKE_PAD (3, 2, 70);
+       MAKE_PAD (3, 3, 71);
+       MAKE_PAD (3, 4, 72);
+       MAKE_PAD (3, 5, 73);
+       MAKE_PAD (3, 6, 74);
+       MAKE_PAD (3, 7, 75);
+       MAKE_PAD (4, 0, 60);
+       MAKE_PAD (4, 1, 61);
+       MAKE_PAD (4, 2, 62);
+       MAKE_PAD (4, 3, 63);
+       MAKE_PAD (4, 4, 64);
+       MAKE_PAD (4, 5, 65);
+       MAKE_PAD (4, 6, 66);
+       MAKE_PAD (4, 7, 67);
+       MAKE_PAD (5, 0, 52);
+       MAKE_PAD (5, 1, 53);
+       MAKE_PAD (5, 2, 54);
+       MAKE_PAD (5, 3, 56);
+       MAKE_PAD (5, 4, 56);
+       MAKE_PAD (5, 5, 57);
+       MAKE_PAD (5, 6, 58);
+       MAKE_PAD (5, 7, 59);
+       MAKE_PAD (6, 0, 44);
+       MAKE_PAD (6, 1, 45);
+       MAKE_PAD (6, 2, 46);
+       MAKE_PAD (6, 3, 47);
+       MAKE_PAD (6, 4, 48);
+       MAKE_PAD (6, 5, 49);
+       MAKE_PAD (6, 6, 50);
+       MAKE_PAD (6, 7, 51);
+       MAKE_PAD (7, 0, 36);
+       MAKE_PAD (7, 1, 37);
+       MAKE_PAD (7, 2, 38);
+       MAKE_PAD (7, 3, 39);
+       MAKE_PAD (7, 4, 40);
+       MAKE_PAD (7, 5, 41);
+       MAKE_PAD (7, 6, 42);
+       MAKE_PAD (7, 7, 43);
+
+       /* Now color buttons */
+
+       Button *button;
+
+#define MAKE_COLOR_BUTTON(i,cc) \
+       button = new ColorButton ((i), (cc)); \
+       cc_button_map.insert (make_pair (button->controller_number(), button)); \
+       id_button_map.insert (make_pair (button->id, button));
+#define MAKE_COLOR_BUTTON_PRESS(i,cc,p)\
+       button = new ColorButton ((i), (cc), (p)); \
+       cc_button_map.insert (make_pair (button->controller_number(), button)); \
+       id_button_map.insert (make_pair (button->id, button))
+
+       MAKE_COLOR_BUTTON (Upper1, 102);
+       MAKE_COLOR_BUTTON (Upper2, 103);
+       MAKE_COLOR_BUTTON (Upper3, 104);
+       MAKE_COLOR_BUTTON (Upper4, 105);
+       MAKE_COLOR_BUTTON (Upper5, 106);
+       MAKE_COLOR_BUTTON (Upper6, 107);
+       MAKE_COLOR_BUTTON (Upper7, 108);
+       MAKE_COLOR_BUTTON (Upper8, 109);
+       MAKE_COLOR_BUTTON (Lower1, 21);
+       MAKE_COLOR_BUTTON (Lower2, 22);
+       MAKE_COLOR_BUTTON (Lower3, 23);
+       MAKE_COLOR_BUTTON (Lower4, 24);
+       MAKE_COLOR_BUTTON (Lower5, 25);
+       MAKE_COLOR_BUTTON (Lower6, 26);
+       MAKE_COLOR_BUTTON (Lower7, 27);
+       MAKE_COLOR_BUTTON (Mute, 60);
+       MAKE_COLOR_BUTTON (Solo, 61);
+       MAKE_COLOR_BUTTON (Stop, 29);
+       MAKE_COLOR_BUTTON (Fwd32ndT, 43);
+       MAKE_COLOR_BUTTON (Fwd32nd,42 );
+       MAKE_COLOR_BUTTON (Fwd16thT, 41);
+       MAKE_COLOR_BUTTON (Fwd16th, 40);
+       MAKE_COLOR_BUTTON (Fwd8thT, 39 );
+       MAKE_COLOR_BUTTON (Fwd8th, 38);
+       MAKE_COLOR_BUTTON (Fwd4trT, 37);
+       MAKE_COLOR_BUTTON (Fwd4tr, 36);
+       MAKE_COLOR_BUTTON (Automate, 89);
+       MAKE_COLOR_BUTTON_PRESS (RecordEnable, 86, &Push::button_recenable);
+       MAKE_COLOR_BUTTON_PRESS (Play, 85, &Push2::button_play);
+
+#define MAKE_WHITE_BUTTON(i,cc)\
+       button = new WhiteButton ((i), (cc)); \
+       cc_button_map.insert (make_pair (button->controller_number(), button)); \
+       id_button_map.insert (make_pair (button->id, button))
+#define MAKE_WHITE_BUTTON_PRESS(i,cc,p)\
+       button = new WhiteButton ((i), (cc), (p)); \
+       cc_button_map.insert (make_pair (button->controller_number(), button)); \
+       id_button_map.insert (make_pair (button->id, button))
+
+       MAKE_WHITE_BUTTON (TapTempo, 3);
+       MAKE_WHITE_BUTTON (Metronome, 9);
+       MAKE_WHITE_BUTTON (Setup, 30);
+       MAKE_WHITE_BUTTON (User, 59);
+       MAKE_WHITE_BUTTON (Delete, 118);
+       MAKE_WHITE_BUTTON (AddDevice, 52);
+       MAKE_WHITE_BUTTON (Device, 110);
+       MAKE_WHITE_BUTTON (Mix, 112);
+       MAKE_WHITE_BUTTON (Undo, 119);
+       MAKE_WHITE_BUTTON (AddTrack, 53);
+       MAKE_WHITE_BUTTON (Browse, 113);
+       MAKE_WHITE_BUTTON (Convert, 35);
+       MAKE_WHITE_BUTTON (DoubleLoop, 117);
+       MAKE_WHITE_BUTTON (Quantize, 116);
+       MAKE_WHITE_BUTTON (Duplicate, 88);
+       MAKE_WHITE_BUTTON (New, 87);
+       MAKE_WHITE_BUTTON (FixedLength, 90);
+       MAKE_WHITE_BUTTON_PRESS (Up, 46, &Push2::button_up);
+       MAKE_WHITE_BUTTON (Right, 45);
+       MAKE_WHITE_BUTTON_PRESS (Down, 47, &Push2::button_down);
+       MAKE_WHITE_BUTTON (Left, 44);
+       MAKE_WHITE_BUTTON (Repeat, 56);
+       MAKE_WHITE_BUTTON (Accent, 57);
+       MAKE_WHITE_BUTTON (Scale, 58);
+       MAKE_WHITE_BUTTON (Layout, 31);
+       MAKE_WHITE_BUTTON (OctaveUp, 55);
+       MAKE_WHITE_BUTTON (PageRight, 63);
+       MAKE_WHITE_BUTTON (OctaveDown, 54);
+       MAKE_WHITE_BUTTON (PageLeft, 62);
+       MAKE_WHITE_BUTTON (Shift, 49);
+       MAKE_WHITE_BUTTON (Select, 48);
+}
+
+void
+Push2::thread_init ()
+{
+       struct sched_param rtparam;
+
+       pthread_set_name (event_loop_name().c_str());
+
+       PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
+       ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
+
+       memset (&rtparam, 0, sizeof (rtparam));
+       rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
+
+       if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
+               // do we care? not particularly.
+       }
+}
+
+void
+Push2::connect_session_signals()
+{
+       // receive routes added
+       //session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
+       // receive VCAs added
+       //session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_vca_added, this, _1), this);
+
+       // receive record state toggled
+       session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_record_state_changed, this), this);
+       // receive transport state changed
+       session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_transport_state_changed, this), this);
+       session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_loop_state_changed, this), this);
+       // receive punch-in and punch-out
+       Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
+       session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
+       // receive rude solo changed
+       session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_solo_active_changed, this, _1), this);
+}
+
+void
+Push2::notify_record_state_changed ()
+{
+       IDButtonMap::iterator b = id_button_map.find (RecordEnable);
+
+       if (b == id_button_map.end()) {
+               return;
+       }
+
+       if (session->actively_recording ()) {
+               b->second->set_state (LED::OneShot24th);
+               b->second->set_color (127);
+       } else {
+               b->second->set_state (LED::Off);
+       }
+
+       write (0, b->second->state_msg());
+}
+
+void
+Push2::notify_transport_state_changed ()
+{
+       cerr << "ts change, id button map holds " << id_button_map.size() << endl;
+
+       IDButtonMap::iterator b = id_button_map.find (Play);
+
+       if (b == id_button_map.end()) {
+               cerr << " no button\n";
+               return;
+       }
+
+       if (session->transport_rolling()) {
+               b->second->set_state (LED::OneShot24th);
+               b->second->set_color (125);
+       } else {
+               b->second->set_state (LED::Off);
+       }
+
+       write (0, b->second->state_msg());
+}
+
+void
+Push2::notify_loop_state_changed ()
+{
+}
+
+void
+Push2::notify_parameter_changed (std::string)
+{
+}
+
+void
+Push2::notify_solo_active_changed (bool yn)
+{
+       IDButtonMap::iterator b = id_button_map.find (Solo);
+
+       if (b == id_button_map.end()) {
+               return;
+       }
+
+       if (yn) {
+               b->second->set_state (LED::Blinking24th);
+       } else {
+               b->second->set_state (LED::Off);
+       }
+
+       write (0, b->second->state_msg());
+}
+
+XMLNode&
+Push2::get_state()
+{
+       XMLNode& node (ControlProtocol::get_state());
+
+       DEBUG_TRACE (DEBUG::Push2, "Push2::get_state done\n");
+
+       return node;
+}
+
+int
+Push2::set_state (const XMLNode & node, int version)
+{
+       DEBUG_TRACE (DEBUG::Push2, string_compose ("Push2::set_state: active %1\n", active()));
+
+       int retval = 0;
+
+       if (ControlProtocol::set_state (node, version)) {
+               return -1;
+       }
+
+
+       return retval;
+}
index aa3e7da3dd30f00ed15d2b3e437a329dfee871f6..48359b6637af26bd87d65b60676da061cfb6e17a 100644 (file)
@@ -70,6 +70,8 @@ class Push2 : public ARDOUR::ControlProtocol
        static void* request_factory (uint32_t);
 
        int set_active (bool yn);
        static void* request_factory (uint32_t);
 
        int set_active (bool yn);
+       XMLNode& get_state();
+       int set_state (const XMLNode & node, int version);
 
    private:
        libusb_device_handle *handle;
 
    private:
        libusb_device_handle *handle;
@@ -79,6 +81,7 @@ class Push2 : public ARDOUR::ControlProtocol
        int  device_buffer;
        Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
        sigc::connection vblank_connection;
        int  device_buffer;
        Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
        sigc::connection vblank_connection;
+       sigc::connection periodic_connection;
 
        static const int cols;
        static const int rows;
 
        static const int cols;
        static const int rows;
@@ -91,6 +94,60 @@ class Push2 : public ARDOUR::ControlProtocol
        int render ();
        bool vblank ();
 
        int render ();
        bool vblank ();
 
+       enum ButtonID {
+               TapTempo,
+               Metronome,
+               Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
+               Setup,
+               User,
+               Delete,
+               AddDevice,
+               Device,
+               Mix,
+               Undo,
+               AddTrack,
+               Browse,
+               Clip,
+               Mute,
+               Solo,
+               Stop,
+               Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8,
+               Master,
+               Convert,
+               DoubleLoop,
+               Quantize,
+               Duplicate,
+               New,
+               FixedLength,
+               Automate,
+               RecordEnable,
+               Play,
+               Fwd32ndT,
+               Fwd32nd,
+               Fwd16thT,
+               Fwd16th,
+               Fwd8thT,
+               Fwd8th,
+               Fwd4trT,
+               Fwd4tr,
+               Up,
+               Right,
+               Down,
+               Left,
+               Repeat,
+               Accent,
+               Scale,
+               Layout,
+               Note,
+               Session,
+               OctaveUp,
+               PageRight,
+               OctaveDown,
+               PageLeft,
+               Shift,
+               Select
+       };
+
        struct LED
        {
                enum State {
        struct LED
        {
                enum State {
@@ -112,42 +169,151 @@ class Push2 : public ARDOUR::ControlProtocol
                        Blinking2th
                };
 
                        Blinking2th
                };
 
-               enum Type {
-                       Pad,
-                       ColorButton,
-                       WhiteButton,
-                       TouchStrip,
-               };
+               LED (uint8_t e) : _extra (e), _color_index (0), _state (Off) {}
+               virtual ~LED() {}
 
 
+               uint8_t extra () const { return _extra; }
+               uint8_t color_index () const { return _color_index; }
+               State   state () const { return _state; }
 
 
+               void set_color (uint8_t color_index);
+               void set_state (State state);
 
 
-               uint8_t id;
-               Type    type;
-               uint8_t extra;
-               uint8_t color_index;
-               uint8_t state;
+               virtual MidiByteArray state_msg() const = 0;
 
 
-               LED (uint8_t i, Type t, uint8_t e) : id (i), type (t), extra (e), color_index (0), state (Off) {}
-               LED () : id (0), type (Pad), extra (0), color_index (0), state (Off) {}
+            protected:
+               uint8_t _extra;
+               uint8_t _color_index;
+               State   _state;
+       };
 
 
-               MidiByteArray update ();
+       struct Pad : public LED {
+               Pad (int xx, int yy, uint8_t ex)
+                       : LED (ex)
+                       , x (xx)
+                       , y (yy) {}
 
 
-               void set_color (uint8_t color_index);
-               void set_state (State state);
+               MidiByteArray state_msg () const { return MidiByteArray (3, 0x90|_state, _extra, (_state == Off) ? 0 : _color_index); }
+
+               int coord () const { return (y * 8) + x; }
+               int note_number() const { return extra(); }
+
+               int x;
+               int y;
+       };
+
+       struct Button : public LED {
+               Button (ButtonID bb, uint8_t ex)
+                       : LED (ex)
+                       , id (bb)
+                       , press_method (&Push2::relax)
+                       , release_method (&Push2::relax)
+               {}
+
+               Button (ButtonID bb, uint8_t ex, void (Push2::*press)())
+                       : LED (ex)
+                       , id (bb)
+                       , press_method (press)
+                       , release_method (&Push2::relax)
+               {}
+
+               Button (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
+                       : LED (ex)
+                       , id (bb)
+                       , press_method (press)
+                       , release_method (release)
+               {}
+
+               MidiByteArray state_msg () const { return MidiByteArray (3, 0xb0|_state, _extra, (_state == Off) ? 0 : _color_index); }
+               int controller_number() const { return extra(); }
+
+               ButtonID id;
+               void (Push2::*press_method)();
+               void (Push2::*release_method)();
+       };
+
+       struct ColorButton : public Button {
+               ColorButton (ButtonID bb, uint8_t ex)
+                       : Button (bb, ex) {}
+
+
+               ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
+                       : Button (bb, ex, press) {}
+
+               ColorButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
+                       : Button (bb, ex, press, release) {}
        };
 
        };
 
-       std::map<int,LED> leds;
-       void set_led_color (uint32_t id, uint8_t color_index);
-       void set_led_state (uint32_t id, LED::State);
-       void build_led_map ();
+       struct WhiteButton : public Button {
+               WhiteButton (ButtonID bb, uint8_t ex)
+                       : Button (bb, ex) {}
+
+               WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)())
+                       : Button (bb, ex, press) {}
+
+               WhiteButton (ButtonID bb, uint8_t ex, void (Push2::*press)(), void (Push2::*release)())
+                       : Button (bb, ex, press, release) {}
+       };
+
+       void relax () {}
+
+       /* map of Buttons by CC */
+       typedef std::map<int,Button*> CCButtonMap;
+       CCButtonMap cc_button_map;
+       /* map of Buttons by ButtonID */
+       typedef std::map<ButtonID,Button*> IDButtonMap;
+       IDButtonMap id_button_map;
+
+       /* map of Pads by note number */
+       typedef std::map<int,Pad*> NNPadMap;
+       NNPadMap nn_pad_map;
+       /* map of Pads by coordinate
+        *
+        * coord = row * 64 + column;
+        *
+        * rows start at top left
+        */
+       typedef std::map<int,Pad*> CoordPadMap;
+       CoordPadMap coord_pad_map;
+
+       void set_button_color (ButtonID, uint8_t color_index);
+       void set_button_state (ButtonID, LED::State);
+       void set_led_color (ButtonID, uint8_t color_index);
+       void set_led_state (ButtonID, LED::State);
+
+       void build_maps ();
 
        MIDI::Port* _input_port[2];
        MIDI::Port* _output_port[2];
        boost::shared_ptr<ARDOUR::Port> _async_in[2];
        boost::shared_ptr<ARDOUR::Port> _async_out[2];
 
 
        MIDI::Port* _input_port[2];
        MIDI::Port* _output_port[2];
        boost::shared_ptr<ARDOUR::Port> _async_in[2];
        boost::shared_ptr<ARDOUR::Port> _async_out[2];
 
+       void connect_to_parser ();
+       void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t);
+       void handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes*);
+       void handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes*);
+       void handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes*);
+       void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
+
        void write (int port, const MidiByteArray&);
        bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
        void write (int port, const MidiByteArray&);
        bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
+       bool periodic ();
+
+       void thread_init ();
+
+       PBD::ScopedConnectionList session_connections;
+       void connect_session_signals ();
+       void notify_record_state_changed ();
+       void notify_transport_state_changed ();
+       void notify_loop_state_changed ();
+       void notify_parameter_changed (std::string);
+       void notify_solo_active_changed (bool);
+
+       /* Button methods */
+       void button_play ();
+       void button_recenable ();
+       void button_up ();
+       void button_down ();
 };
 
 
 };
 
 
index b69a13ec0eadb05eff8355c1b4293658d47b73fa..2acf74842dcd6e233d80b085aca6f5a59eb3fd97 100644 (file)
@@ -21,6 +21,7 @@ def build(bld):
     obj = bld(features = 'cxx cxxshlib')
     obj.source = '''
             push2.cc
     obj = bld(features = 'cxx cxxshlib')
     obj.source = '''
             push2.cc
+            buttons.cc
            interface.cc
             midi_byte_array.cc
             leds.cc
            interface.cc
             midi_byte_array.cc
             leds.cc