push2: port registration, LED setup

This commit is contained in:
Paul Davis
2016-06-16 10:02:46 -04:00
parent e0be45de38
commit 67698b8232
7 changed files with 441 additions and 5 deletions

150
libs/surfaces/push2/leds.cc Normal file
View File

@@ -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)));
}

View File

@@ -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;
}

View File

@@ -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

View 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);
}

View File

@@ -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<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&);
};

View File

@@ -1,4 +0,0 @@
#include <libusb.h>
#include <unistd.h>
#include <assert.h>

View 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"' ]