push2: working bidirectional communication, some transport control/display (LED only); some scrolling
This commit is contained in:
@@ -453,6 +453,8 @@ ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
|
||||
delete cpi->state;
|
||||
cpi->state = new XMLNode (**citer);
|
||||
|
||||
std::cerr << "protocol " << prop->value() << " active ? " << active << std::endl;
|
||||
|
||||
if (active) {
|
||||
if (_session) {
|
||||
instantiate (*cpi);
|
||||
@@ -466,6 +468,8 @@ ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
|
||||
cpi->requested = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::cerr << "protocol " << prop->value() << " not found\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
libs/surfaces/push2/buttons.cc
Normal file
34
libs/surfaces/push2/buttons.cc
Normal file
@@ -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 ();
|
||||
}
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
@@ -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<Push2Request> (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<Glib::TimeoutSource> 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<AsyncMIDIPort*>(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;
|
||||
}
|
||||
|
||||
@@ -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<Cairo::ImageSurface> 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 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 ();
|
||||
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);
|
||||
|
||||
virtual MidiByteArray state_msg() const = 0;
|
||||
|
||||
protected:
|
||||
uint8_t _extra;
|
||||
uint8_t _color_index;
|
||||
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 ();
|
||||
struct Pad : public LED {
|
||||
Pad (int xx, int yy, uint8_t ex)
|
||||
: LED (ex)
|
||||
, x (xx)
|
||||
, y (yy) {}
|
||||
|
||||
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) {}
|
||||
};
|
||||
|
||||
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<int,Button*> CCButtonMap;
|
||||
CCButtonMap cc_button_map;
|
||||
/* map of Buttons by ButtonID */
|
||||
typedef std::map<ButtonID,Button*> IDButtonMap;
|
||||
IDButtonMap id_button_map;
|
||||
|
||||
/* map of Pads by note number */
|
||||
typedef std::map<int,Pad*> NNPadMap;
|
||||
NNPadMap nn_pad_map;
|
||||
/* map of Pads by coordinate
|
||||
*
|
||||
* coord = row * 64 + column;
|
||||
*
|
||||
* rows start at top left
|
||||
*/
|
||||
typedef std::map<int,Pad*> 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<ARDOUR::Port> _async_in[2];
|
||||
boost::shared_ptr<ARDOUR::Port> _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 ();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user