From 4991bf5a1a72720e2f91e2b9e91cfc034c384436 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 16 Jun 2016 14:06:16 -0400 Subject: push2: working bidirectional communication, some transport control/display (LED only); some scrolling --- libs/surfaces/push2/buttons.cc | 34 ++++ libs/surfaces/push2/leds.cc | 133 +------------- libs/surfaces/push2/push2.cc | 382 ++++++++++++++++++++++++++++++++++++++++- libs/surfaces/push2/push2.h | 206 +++++++++++++++++++--- libs/surfaces/push2/wscript | 1 + 5 files changed, 598 insertions(+), 158 deletions(-) create mode 100644 libs/surfaces/push2/buttons.cc (limited to 'libs/surfaces') diff --git a/libs/surfaces/push2/buttons.cc b/libs/surfaces/push2/buttons.cc new file mode 100644 index 0000000000..1db04f486e --- /dev/null +++ b/libs/surfaces/push2/buttons.cc @@ -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 (); +} diff --git a/libs/surfaces/push2/leds.cc b/libs/surfaces/push2/leds.cc index 1e5423e17a..75921f1b49 100644 --- a/libs/surfaces/push2/leds.cc +++ b/libs/surfaces/push2/leds.cc @@ -10,141 +10,12 @@ using std::min; 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) { - 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))); -} diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index 4920a18e5e..9b6d84dbe3 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -24,6 +24,8 @@ #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" @@ -48,14 +50,14 @@ const int Push2::pixels_per_row = 1024; #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 (name()) , handle (0) , device_buffer (0) , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows)) { - build_led_map (); + build_maps (); } 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()); + connect_to_parser (); + return 0; } @@ -137,6 +141,8 @@ Push2::close () _async_out[1].reset ((ARDOUR::Port*) 0); vblank_connection.disconnect (); + periodic_connection.disconnect (); + session_connections.drop_connections (); if (handle) { libusb_release_interface (handle, 0x00); @@ -298,7 +304,7 @@ Push2::set_active (bool yn) return -1; } - // connect_session_signals (); + connect_session_signals (); /* 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()); + + Glib::RefPtr 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 (); @@ -356,6 +367,7 @@ void Push2::write (int port, const MidiByteArray& data) { /* immediate delivery */ + cerr << data << endl; _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) { - 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(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(); - // port->parse (now); + port->parse (now); } 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; +} diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index aa3e7da3dd..48359b6637 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -70,6 +70,8 @@ class Push2 : public ARDOUR::ControlProtocol 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; @@ -79,6 +81,7 @@ class Push2 : public ARDOUR::ControlProtocol int device_buffer; Cairo::RefPtr frame_buffer; sigc::connection vblank_connection; + sigc::connection periodic_connection; static const int cols; static const int rows; @@ -91,6 +94,60 @@ class Push2 : public ARDOUR::ControlProtocol 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 { @@ -112,42 +169,151 @@ class Push2 : public ARDOUR::ControlProtocol 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 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 CCButtonMap; + CCButtonMap cc_button_map; + /* map of Buttons by ButtonID */ + typedef std::map IDButtonMap; + IDButtonMap id_button_map; + + /* map of Pads by note number */ + typedef std::map NNPadMap; + NNPadMap nn_pad_map; + /* map of Pads by coordinate + * + * coord = row * 64 + column; + * + * rows start at top left + */ + typedef std::map 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 _async_in[2]; boost::shared_ptr _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); + 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 (); }; diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript index b69a13ec0e..2acf74842d 100644 --- a/libs/surfaces/push2/wscript +++ b/libs/surfaces/push2/wscript @@ -21,6 +21,7 @@ def build(bld): obj = bld(features = 'cxx cxxshlib') obj.source = ''' push2.cc + buttons.cc interface.cc midi_byte_array.cc leds.cc -- cgit v1.2.3