From 67698b8232c8e99c0de65a5444f1b3b86f4f6297 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 16 Jun 2016 10:02:46 -0400 Subject: [PATCH] push2: port registration, LED setup --- libs/surfaces/push2/leds.cc | 150 +++++++++++++++++++++++++ libs/surfaces/push2/midi_byte_array.cc | 96 ++++++++++++++++ libs/surfaces/push2/midi_byte_array.h | 76 +++++++++++++ libs/surfaces/push2/push2.cc | 49 +++++++- libs/surfaces/push2/push2.h | 69 ++++++++++++ libs/surfaces/push2/render.cc | 4 - libs/surfaces/push2/wscript | 2 + 7 files changed, 441 insertions(+), 5 deletions(-) create mode 100644 libs/surfaces/push2/leds.cc create mode 100644 libs/surfaces/push2/midi_byte_array.cc create mode 100644 libs/surfaces/push2/midi_byte_array.h delete mode 100644 libs/surfaces/push2/render.cc diff --git a/libs/surfaces/push2/leds.cc b/libs/surfaces/push2/leds.cc new file mode 100644 index 0000000000..1e5423e17a --- /dev/null +++ b/libs/surfaces/push2/leds.cc @@ -0,0 +1,150 @@ +#include + +#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 index 0000000000..45d0439a75 --- /dev/null +++ b/libs/surfaces/push2/midi_byte_array.cc @@ -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 +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +MidiByteArray::MidiByteArray (size_t size, MIDI::byte array[]) + : std::vector() +{ + for (size_t i = 0; i < size; ++i) + { + push_back (array[i]); + } +} + +MidiByteArray::MidiByteArray (size_t count, MIDI::byte first, ...) + : vector() +{ + 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 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 index 0000000000..3d3bcecd28 --- /dev/null +++ b/libs/surfaces/push2/midi_byte_array.h @@ -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 +#include + +#include + +//#include +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 +{ +public: + MidiByteArray() : std::vector() {} + + 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 diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc index be25357e26..92e05cfee1 100644 --- a/libs/surfaces/push2/push2.cc +++ b/libs/surfaces/push2/push2.cc @@ -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(_async_in[1]).get(); + _output_port[1] = boost::dynamic_pointer_cast(_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(_async_in[1]).get(); + _output_port[1] = boost::dynamic_pointer_cast(_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); +} diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h index fb301a62a7..1b8c948986 100644 --- a/libs/surfaces/push2/push2.h +++ b/libs/surfaces/push2/push2.h @@ -35,10 +35,22 @@ #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 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 _async_in[2]; + boost::shared_ptr _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 index 27a145df1d..0000000000 --- a/libs/surfaces/push2/render.cc +++ /dev/null @@ -1,4 +0,0 @@ -#include -#include -#include - diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript index 379f1199d7..b69a13ec0e 100644 --- a/libs/surfaces/push2/wscript +++ b/libs/surfaces/push2/wscript @@ -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"' ] -- 2.30.2