push2: port registration, LED setup
This commit is contained in:
150
libs/surfaces/push2/leds.cc
Normal file
150
libs/surfaces/push2/leds.cc
Normal 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)));
|
||||
}
|
||||
96
libs/surfaces/push2/midi_byte_array.cc
Normal file
96
libs/surfaces/push2/midi_byte_array.cc
Normal 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;
|
||||
}
|
||||
76
libs/surfaces/push2/midi_byte_array.h
Normal file
76
libs/surfaces/push2/midi_byte_array.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#include <libusb.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
@@ -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"' ]
|
||||
|
||||
Reference in New Issue
Block a user