push2: port registration, LED setup
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 16 Jun 2016 14:02:46 +0000 (10:02 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Sep 2016 19:59:29 +0000 (14:59 -0500)
libs/surfaces/push2/leds.cc [new file with mode: 0644]
libs/surfaces/push2/midi_byte_array.cc [new file with mode: 0644]
libs/surfaces/push2/midi_byte_array.h [new file with mode: 0644]
libs/surfaces/push2/push2.cc
libs/surfaces/push2/push2.h
libs/surfaces/push2/render.cc [deleted file]
libs/surfaces/push2/wscript

diff --git a/libs/surfaces/push2/leds.cc b/libs/surfaces/push2/leds.cc
new file mode 100644 (file)
index 0000000..1e5423e
--- /dev/null
@@ -0,0 +1,150 @@
+#include <algorithm>
+
+#include "push2.h"
+
+using namespace ArdourSurface;
+using std::make_pair;
+using std::max;
+using std::min;
+
+void
+Push2::LED::set_color (uint8_t ci)
+{
+       color_index = max (uint8_t(0), min (uint8_t(127), ci));
+}
+
+void
+Push2::LED::set_state (LED::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/midi_byte_array.cc b/libs/surfaces/push2/midi_byte_array.cc
new file mode 100644 (file)
index 0000000..45d0439
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+       Copyright (C) 2006,2007 John Anderson
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "midi_byte_array.h"
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <algorithm>
+#include <cstdarg>
+#include <iomanip>
+#include <stdexcept>
+
+using namespace std;
+
+MidiByteArray::MidiByteArray (size_t size, MIDI::byte array[])
+  : std::vector<MIDI::byte>()
+{
+       for  (size_t i = 0; i < size; ++i)
+       {
+               push_back (array[i]);
+       }
+}
+
+MidiByteArray::MidiByteArray (size_t count, MIDI::byte first, ...)
+  : vector<MIDI::byte>()
+{
+       push_back (first);
+       va_list var_args;
+       va_start (var_args, first);
+       for  (size_t i = 1; i < count; ++i)
+       {
+               MIDI::byte b = va_arg (var_args, int);
+               push_back (b);
+       }
+       va_end (var_args);
+}
+
+
+void MidiByteArray::copy (size_t count, MIDI::byte * arr)
+{
+       for (size_t i = 0; i < count; ++i) {
+               push_back (arr[i]);
+       }
+}
+
+MidiByteArray & operator <<  (MidiByteArray & mba, const MIDI::byte & b)
+{
+       mba.push_back (b);
+       return mba;
+}
+
+MidiByteArray & operator <<  (MidiByteArray & mba, const MidiByteArray & barr)
+{
+       back_insert_iterator<MidiByteArray> bit (mba);
+       copy (barr.begin(), barr.end(), bit);
+       return mba;
+}
+
+ostream & operator <<  (ostream & os, const MidiByteArray & mba)
+{
+       os << "[";
+       char fill = os.fill('0');
+       for (MidiByteArray::const_iterator it = mba.begin(); it != mba.end(); ++it) {
+               if  (it != mba.begin()) os << " ";
+               os << hex << setw(2) << (int)*it;
+       }
+       os.fill (fill);
+       os << dec;
+       os << "]";
+       return os;
+}
+
+MidiByteArray & operator <<  (MidiByteArray & mba, const std::string & st)
+{
+       /* note that this assumes that "st" is ASCII encoded
+        */
+
+       mba.insert (mba.end(), st.begin(), st.end());
+       return mba;
+}
diff --git a/libs/surfaces/push2/midi_byte_array.h b/libs/surfaces/push2/midi_byte_array.h
new file mode 100644 (file)
index 0000000..3d3bcec
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+       Copyright (C) 2006,2007 John Anderson
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef midi_byte_array_h
+#define midi_byte_array_h
+
+#include <iostream>
+#include <vector>
+
+#include <boost/shared_array.hpp>
+
+//#include <midi++/types.h>
+namespace MIDI {
+       typedef unsigned char byte;
+}
+
+/**
+       To make building arrays of bytes easier. Thusly:
+
+       MidiByteArray mba;
+       mba << 0xf0 << 0x00 << 0xf7;
+
+       MidiByteArray buf;
+       buf << mba;
+
+       MidiByteArray direct( 3, 0xf0, 0x00, 0xf7 );
+
+       cout << mba << endl;
+       cout << buf << endl;
+       cout << direct << endl;
+
+       will all result in "f0 00 f7" being output to stdout
+*/
+class MidiByteArray : public std::vector<MIDI::byte>
+{
+public:
+       MidiByteArray() : std::vector<MIDI::byte>() {}
+
+       MidiByteArray( size_t count, MIDI::byte array[] );
+
+       /**
+               Accepts a preceding count, and then a list of bytes
+       */
+       MidiByteArray( size_t count, MIDI::byte first, ... );
+
+       /// copy the given number of bytes from the given array
+       void copy( size_t count, MIDI::byte arr[] );
+};
+
+/// append the given byte to the end of the array
+MidiByteArray & operator << ( MidiByteArray & mba, const MIDI::byte & b );
+
+/// append the given string to the end of the array
+MidiByteArray & operator << ( MidiByteArray & mba, const std::string & );
+
+/// append the given array to the end of this array
+MidiByteArray & operator << ( MidiByteArray & mba, const MidiByteArray & barr );
+
+/// output the bytes as hex to the given stream
+std::ostream & operator << ( std::ostream & os, const MidiByteArray & mba );
+
+#endif
index be25357e267cca82d8f79b2ed110462836e894b4..92e05cfee17f2b10e032caccdd00bab64bdbb4d1 100644 (file)
@@ -25,6 +25,9 @@
 #include "pbd/failed_constructor.h"
 
 #include "ardour/debug.h"
+#include "ardour/audioengine.h"
+#include "ardour/async_midi_port.h"
+#include "ardour/midiport_manager.h"
 
 #include "push2.h"
 
@@ -52,6 +55,7 @@ Push2::Push2 (Session& s)
        , device_buffer (0)
        , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
 {
+       build_led_map ();
 }
 
 Push2::~Push2 ()
@@ -62,11 +66,15 @@ Push2::~Push2 ()
 int
 Push2::open ()
 {
+       int err;
+
        if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
                return -1;
        }
 
-       libusb_claim_interface (handle, 0x00);
+       if ((err = libusb_claim_interface (handle, 0x00))) {
+               return -1;
+       }
 
        device_frame_buffer[0] = new uint16_t[rows*pixels_per_row];
        device_frame_buffer[1] = new uint16_t[rows*pixels_per_row];
@@ -80,12 +88,44 @@ Push2::open ()
        frame_header[3] = 0x89;
        memset (&frame_header[4], 0, 12);
 
+       /* setup ports */
+
+       _async_in[0]  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in1"), true);
+       _async_out[0] = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out1"), true);
+
+       if (_async_in[0] == 0 || _async_out[0] == 0) {
+               return -1;
+       }
+
+       _input_port[1] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in[1]).get();
+       _output_port[1] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out[1]).get();
+
+       _async_in[1]  = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("push2 in2"), true);
+       _async_out[1] = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("push2 out2"), true);
+
+       if (_async_in[1] == 0 || _async_out[1] == 0) {
+               return -1;
+       }
+
+       _input_port[1] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in[1]).get();
+       _output_port[1] = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out[1]).get();
+
        return 0;
 }
 
 int
 Push2::close ()
 {
+       AudioEngine::instance()->unregister_port (_async_in[0]);
+       AudioEngine::instance()->unregister_port (_async_out[0]);
+       AudioEngine::instance()->unregister_port (_async_in[1]);
+       AudioEngine::instance()->unregister_port (_async_out[1]);
+
+       _async_in[0].reset ((ARDOUR::Port*) 0);
+       _async_out[0].reset ((ARDOUR::Port*) 0);
+       _async_in[1].reset ((ARDOUR::Port*) 0);
+       _async_out[1].reset ((ARDOUR::Port*) 0);
+
        vblank_connection.disconnect ();
 
        if (handle) {
@@ -303,3 +343,10 @@ Push2::set_active (bool yn)
 
        return 0;
 }
+
+void
+Push2::write (int port, const MidiByteArray& data)
+{
+       /* immediate delivery */
+       _output_port[port]->write (&data[0], data.size(), 0);
+}
index fb301a62a7c9e1e3f0d0e0ff8f60844ad5332fe7..1b8c948986e4debe8149a7961dea8e7810b27172 100644 (file)
 #include "ardour/types.h"
 #include "control_protocol/control_protocol.h"
 
+#include "midi_byte_array.h"
+
 namespace Cairo {
        class ImageSurface;
 }
 
+namespace MIDI {
+       class Parser;
+       class Port;
+}
+
+namespace ARDOUR {
+       class AsyncMIDIPort;
+       class Port;
+}
+
 namespace ArdourSurface {
 
 struct Push2Request : public BaseUI::BaseRequestObject {
@@ -78,6 +90,63 @@ class Push2 : public ARDOUR::ControlProtocol
        int close ();
        int render ();
        bool vblank ();
+
+       struct LED
+       {
+               enum State {
+                       Off,
+                       OneShot24th,
+                       OneShot16th,
+                       OneShot8th,
+                       OneShot4th,
+                       OneShot2th,
+                       Pulsing24th,
+                       Pulsing16th,
+                       Pulsing8th,
+                       Pulsing4th,
+                       Pulsing2th,
+                       Blinking24th,
+                       Blinking16th,
+                       Blinking8th,
+                       Blinking4th,
+                       Blinking2th
+               };
+
+               enum Type {
+                       Pad,
+                       ColorButton,
+                       WhiteButton,
+                       TouchStrip,
+               };
+
+
+
+               uint8_t id;
+               Type    type;
+               uint8_t extra;
+               uint8_t color_index;
+               uint8_t state;
+
+               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) {}
+
+               MidiByteArray update ();
+
+               void set_color (uint8_t color_index);
+               void set_state (State state);
+       };
+
+       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 ();
+
+       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 write (int port, const MidiByteArray&);
 };
 
 
diff --git a/libs/surfaces/push2/render.cc b/libs/surfaces/push2/render.cc
deleted file mode 100644 (file)
index 27a145d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <libusb.h>
-#include <unistd.h>
-#include <assert.h>
-
index 379f1199d749d2e7f629160e366b41d39f09ab89..b69a13ec0eadb05eff8355c1b4293658d47b73fa 100644 (file)
@@ -22,6 +22,8 @@ def build(bld):
     obj.source = '''
             push2.cc
            interface.cc
+            midi_byte_array.cc
+            leds.cc
     '''
     obj.export_includes = ['.']
     obj.defines      = [ 'PACKAGE="ardour_push2"' ]