13
0

MCP: redesign to allow device-specific button IDs, since we know that at least one device (nucleus) does not honor mackie's specification document

git-svn-id: svn://localhost/ardour2/branches/3.0@11972 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-04-14 19:02:54 +00:00
parent 32766ce215
commit 2ed2b61224
21 changed files with 516 additions and 317 deletions

View File

@ -24,11 +24,92 @@
using namespace Mackie;
Control*
Button::factory (Surface& surface, int id, const char* name, Group& group)
Button::factory (Surface& surface, Button::ID bid, int id, const std::string& name, Group& group)
{
Button* b = new Button (id, name, group);
Button* b = new Button (bid, id, name, group);
/* store button with the device-specific ID */
surface.buttons[id] = b;
surface.controls.push_back (b);
group.add (*b);
return b;
}
int
Button::name_to_id (const std::string& name)
{
if (name == "IO") { return IO; }
if (name == "Sends") { return Sends; }
if (name == "Pan") { return Pan; }
if (name == "Plugin") { return Plugin; }
if (name == "Eq") { return Eq; }
if (name == "Dyn") { return Dyn; }
if (name == "Left") { return Left; }
if (name == "Right") { return Right; }
if (name == "ChannelLeft") { return ChannelLeft; }
if (name == "ChannelRight") { return ChannelRight; }
if (name == "Flip") { return Flip; }
if (name == "Edit") { return Edit; }
if (name == "NameValue") { return NameValue; }
if (name == "TimecodeBeats") { return TimecodeBeats; }
if (name == "F1") { return F1; }
if (name == "F2") { return F2; }
if (name == "F3") { return F3; }
if (name == "F4") { return F4; }
if (name == "F5") { return F5; }
if (name == "F6") { return F6; }
if (name == "F7") { return F7; }
if (name == "F8") { return F8; }
if (name == "F9") { return F9; }
if (name == "F10") { return F10; }
if (name == "F11") { return F11; }
if (name == "F12") { return F12; }
if (name == "F13") { return F13; }
if (name == "F14") { return F14; }
if (name == "F15") { return F15; }
if (name == "F16") { return F16; }
if (name == "Shift") { return Shift; }
if (name == "Option") { return Option; }
if (name == "Ctrl") { return Ctrl; }
if (name == "CmdAlt") { return CmdAlt; }
if (name == "On") { return On; }
if (name == "RecReady") { return RecReady; }
if (name == "Undo") { return Undo; }
if (name == "Save") { return Save; }
if (name == "Touch") { return Touch; }
if (name == "Redo") { return Redo; }
if (name == "Marker") { return Marker; }
if (name == "Enter") { return Enter; }
if (name == "Cancel") { return Cancel; }
if (name == "Mixer") { return Mixer; }
if (name == "FrmLeft") { return FrmLeft; }
if (name == "FrmRight") { return FrmRight; }
if (name == "Loop") { return Loop; }
if (name == "PunchIn") { return PunchIn; }
if (name == "PunchOut") { return PunchOut; }
if (name == "Home") { return Home; }
if (name == "End") { return End; }
if (name == "Rewind") { return Rewind; }
if (name == "Ffwd") { return Ffwd; }
if (name == "Stop") { return Stop; }
if (name == "Play") { return Play; }
if (name == "Record") { return Record; }
if (name == "CursorUp") { return CursorUp; }
if (name == "CursorDown") { return CursorDown; }
if (name == "CursorLeft") { return CursorLeft; }
if (name == "CursorRight") { return CursorRight; }
if (name == "Zoom") { return Zoom; }
if (name == "Scrub") { return Scrub; }
if (name == "UserA") { return UserA; }
if (name == "UserB") { return UserB; }
/* Strip buttons */
if (name == "RecEnable") { return RecEnable; }
if (name == "Solo") { return Solo; }
if (name == "Mute") { return Mute; }
if (name == "Select") { return Select; }
if (name == "VSelect") { return VSelect; }
if (name == "FaderTouch") { return FaderTouch; }
return -1;
}

View File

@ -30,92 +30,105 @@ class Surface;
class Button : public Control
{
public:
enum base_id_t {
recenable_base_id = 0x0,
solo_base_id = 0x08,
mute_base_id = 0x10,
select_base_id = 0x18,
vselect_base_id = 0x20,
fader_touch_base_id = 0x68, // 0xe0,
/* These values uniquely identify each possible button that an MCP device may
send. Each DeviceInfo object contains its own set of button definitions that
define what device ID will be sent for each button, and there is no reason
for them to be the same. */
enum ID {
/* Global Buttons */
IO,
Sends,
Pan,
Plugin,
Eq,
Dyn,
Left,
Right,
ChannelLeft,
ChannelRight,
Flip,
Edit,
NameValue,
TimecodeBeats,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
F16,
Shift,
Option,
Ctrl,
CmdAlt,
On,
RecReady,
Undo,
Save,
Touch,
Redo,
Marker,
Enter,
Cancel,
Mixer,
FrmLeft,
FrmRight,
Loop,
PunchIn,
PunchOut,
Home,
End,
Rewind,
Ffwd,
Stop,
Play,
Record,
CursorUp,
CursorDown,
CursorLeft,
CursorRight,
Zoom,
Scrub,
UserA,
UserB,
/* Strip buttons */
RecEnable,
Solo,
Mute,
Select,
VSelect,
FaderTouch,
};
enum ButtonID {
Io = 0x28,
Sends = 0x29,
Pan = 0x2a,
Plugin = 0x2b,
Eq = 0x2c,
Dyn = 0x2d,
Left = 0x2e,
Right = 0x2f,
ChannelLeft = 0x30,
ChannelRight = 0x31,
Flip = 0x32,
Edit = 0x33,
NameValue = 0x34,
TimecodeBeats = 0x35,
F1 = 0x36,
F2 = 0x37,
F3 = 0x38,
F4 = 0x39,
F5 = 0x3a,
F6 = 0x3b,
F7 = 0x3c,
F8 = 0x3d,
F9 = 0x3e,
F10 = 0x3f,
F11 = 0x40,
F12 = 0x41,
F13 = 0x42,
F14 = 0x43,
F15 = 0x44,
F16 = 0x45,
Shift = 0x46,
Option = 0x47,
Ctrl = 0x48,
CmdAlt = 0x49,
On = 0x4a,
RecReady = 0x4b,
Undo = 0x4c,
Save = 0x4d,
Touch = 0x4e,
Redo = 0x4f,
Marker = 0x50,
Enter = 0x51,
Cancel = 0x52,
Mixer = 0x53,
FrmLeft = 0x54,
FrmRight = 0x55,
Loop = 0x56,
PunchIn = 0x57,
PunchOut = 0x58,
Home = 0x59,
End = 0x5a,
Rewind = 0x5b,
Ffwd = 0x5c,
Stop = 0x5d,
Play = 0x5e,
Record = 0x5f,
CursorUp = 0x60,
CursorDown = 0x61,
CursorLeft = 0x62,
CursorRight = 0x63,
Zoom = 0x64,
Scrub = 0x65,
UserA = 0x66,
UserB = 0x67,
};
Button (int id, std::string name, Group & group)
: Control (id, name, group)
, _led (id, name + "_led", group) {}
Button (ID bid, int did, std::string name, Group & group)
: Control (did, name, group)
, _bid (bid)
, _led (did, name + "_led", group) {}
MidiByteArray zero() { return _led.zero (); }
MidiByteArray set_state (LedState ls) { return _led.set_state (ls); }
static Control* factory (Surface&, int id, const char*, Group&);
ID bid() const { return _bid; }
static Control* factory (Surface& surface, Button::ID bid, int id, const std::string&, Group& group);
static int name_to_id (const std::string& name);
private:
ID _bid; /* device independent button ID */
Led _led;
};

View File

@ -83,16 +83,6 @@ ostream & Mackie::operator << (ostream & os, const Mackie::Control & control)
return os;
}
Control*
Jog::factory (Surface& surface, int id, const char* name, Group& group)
{
Jog* j = new Jog (id, name, group);
surface.controls.push_back (j);
surface.controls_by_name["jog"] = j;
group.add (*j);
return j;
}
void
Control::set_normal_control (boost::shared_ptr<AutomationControl> ac)
{

View File

@ -85,7 +85,7 @@ public:
boost::shared_ptr<ARDOUR::AutomationControl> modified_ac;
private:
int _id;
int _id; /* possibly device-dependent ID */
std::string _name;
Group& _group;
bool _in_use;

View File

@ -17,6 +17,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cstdlib>
#include <cstring>
#include <glibmm/miscutils.h>
@ -50,7 +51,83 @@ DeviceInfo::DeviceInfo()
, _has_touch_sense_faders (true)
, _name (X_("Mackie Control Universal Pro"))
{
/* these definitions are based on Mackie's specification for Mackie
* Control Protocol.
*
* Any given device info file can override any or all of these for any reason.
*/
_global_buttons[Button::IO] = GlobalButtonInfo ("io", "assignment", 0x28);
_global_buttons[Button::Sends] = GlobalButtonInfo ("sends", "assignment", 0x29);
_global_buttons[Button::Pan] = GlobalButtonInfo ("pan", "assignment", 0x2a);
_global_buttons[Button::Plugin] = GlobalButtonInfo ("plugin", "assignment", 0x2b);
_global_buttons[Button::Eq] = GlobalButtonInfo ("eq", "assignment", 0x2c);
_global_buttons[Button::Dyn] = GlobalButtonInfo ("dyn", "assignment", 0x2d);
_global_buttons[Button::Left] = GlobalButtonInfo ("left", "bank", 0x2e);
_global_buttons[Button::Right] = GlobalButtonInfo ("right", "bank", 0x2f);
_global_buttons[Button::ChannelLeft] = GlobalButtonInfo ("channel left", "bank", 0x30);
_global_buttons[Button::ChannelRight] = GlobalButtonInfo ("channelright", "bank", 0x31);
_global_buttons[Button::Flip] = GlobalButtonInfo ("flip", "none", 0x32);
_global_buttons[Button::Edit] = GlobalButtonInfo ("edit", "none", 0x33);
_global_buttons[Button::NameValue] = GlobalButtonInfo ("name/value", "display", 0x34);
_global_buttons[Button::TimecodeBeats] = GlobalButtonInfo ("timecode/beats", "display", 0x35);
_global_buttons[Button::F1] = GlobalButtonInfo ("F1", "none", 0x36);
_global_buttons[Button::F2] = GlobalButtonInfo ("F2", "none", 0x37);
_global_buttons[Button::F3] = GlobalButtonInfo ("F3", "none", 0x38);
_global_buttons[Button::F4] = GlobalButtonInfo ("F4", "none", 0x39);
_global_buttons[Button::F5] = GlobalButtonInfo ("F5", "none", 0x3a);
_global_buttons[Button::F6] = GlobalButtonInfo ("F6", "none", 0x3b);
_global_buttons[Button::F7] = GlobalButtonInfo ("F7", "none", 0x3c);
_global_buttons[Button::F8] = GlobalButtonInfo ("F8", "none", 0x3d);
_global_buttons[Button::F9] = GlobalButtonInfo ("F9", "none", 0x3e);
_global_buttons[Button::F10] = GlobalButtonInfo ("F10", "none", 0x3f);
_global_buttons[Button::F11] = GlobalButtonInfo ("F11", "none", 0x40);
_global_buttons[Button::F12] = GlobalButtonInfo ("F12", "none", 0x41);
_global_buttons[Button::F13] = GlobalButtonInfo ("F13", "none", 0x42);
_global_buttons[Button::F14] = GlobalButtonInfo ("F14", "none", 0x43);
_global_buttons[Button::F15] = GlobalButtonInfo ("F15", "none", 0x44);
_global_buttons[Button::F16] = GlobalButtonInfo ("F16", "none", 0x45);
_global_buttons[Button::Shift] = GlobalButtonInfo ("shift", "modifiers", 0x46);
_global_buttons[Button::Option] = GlobalButtonInfo ("option", "modifiers", 0x47);
_global_buttons[Button::Ctrl] = GlobalButtonInfo ("control", "modifiers", 0x48);
_global_buttons[Button::CmdAlt] = GlobalButtonInfo ("cmd_alt", "modifiers", 0x49);
_global_buttons[Button::On] = GlobalButtonInfo ("on", "automation", 0x4a);
_global_buttons[Button::RecReady] = GlobalButtonInfo ("rec_ready", "automation", 0x4b);
_global_buttons[Button::Undo] = GlobalButtonInfo ("undo", "functions", 0x4c);
_global_buttons[Button::Save] = GlobalButtonInfo ("save", "automation", 0x4d);
_global_buttons[Button::Touch] = GlobalButtonInfo ("touch", "automation", 0x4e);
_global_buttons[Button::Redo] = GlobalButtonInfo ("redo", "functions", 0x4f);
_global_buttons[Button::Marker] = GlobalButtonInfo ("marker", "functions", 0x50);
_global_buttons[Button::Enter] = GlobalButtonInfo ("enter", "functions", 0x51);
_global_buttons[Button::Cancel] = GlobalButtonInfo ("cancel", "functions", 0x52);
_global_buttons[Button::Mixer] = GlobalButtonInfo ("mixer", "functions", 0x53);
_global_buttons[Button::FrmLeft] = GlobalButtonInfo ("frm left", "transport", 0x54);
_global_buttons[Button::FrmRight] = GlobalButtonInfo ("frm right", "transport", 0x55);
_global_buttons[Button::Loop] = GlobalButtonInfo ("loop", "transport", 0x56);
_global_buttons[Button::PunchIn] = GlobalButtonInfo ("punch in", "transport", 0x57);
_global_buttons[Button::PunchOut] = GlobalButtonInfo ("punch out", "transport", 0x58);
_global_buttons[Button::Home] = GlobalButtonInfo ("home", "transport", 0x59);
_global_buttons[Button::End] = GlobalButtonInfo ("end", "transport", 0x5a);
_global_buttons[Button::Rewind] = GlobalButtonInfo ("rewind", "transport", 0x5b);
_global_buttons[Button::Ffwd] = GlobalButtonInfo ("ffwd", "transport", 0x5c);
_global_buttons[Button::Stop] = GlobalButtonInfo ("stop", "transport", 0x5d);
_global_buttons[Button::Play] = GlobalButtonInfo ("play", "transport", 0x5e);
_global_buttons[Button::Record] = GlobalButtonInfo ("record", "transport", 0x5f);
_global_buttons[Button::CursorUp] = GlobalButtonInfo ("cursor up", "cursor", 0x60);
_global_buttons[Button::CursorDown] = GlobalButtonInfo ("cursor down", "cursor", 0x61);
_global_buttons[Button::CursorLeft] = GlobalButtonInfo ("cursor left", "cursor", 0x62);
_global_buttons[Button::CursorRight] = GlobalButtonInfo ("cursor right", "cursor", 0x63);
_global_buttons[Button::Zoom] = GlobalButtonInfo ("zoom", "none", 0x64);
_global_buttons[Button::Scrub] = GlobalButtonInfo ("scrub", "none", 0x65);
_global_buttons[Button::UserA] = GlobalButtonInfo ("user a", "user", 0x66);
_global_buttons[Button::UserB] = GlobalButtonInfo ("user b", "user", 0x67);
_strip_buttons[Button::RecEnable], StripButtonInfo (0x0, "recenable");
_strip_buttons[Button::Solo] = StripButtonInfo (0x08, "solo");
_strip_buttons[Button::Mute] = StripButtonInfo (0x10, "mute");
_strip_buttons[Button::Select] = StripButtonInfo (0x18, "select");
_strip_buttons[Button::VSelect] = StripButtonInfo (0x20, "vselect");
_strip_buttons[Button::FaderTouch] = StripButtonInfo (0x68, "fader touch");
}
DeviceInfo::~DeviceInfo()
@ -134,6 +211,50 @@ DeviceInfo::set_state (const XMLNode& node, int /* version */)
_has_touch_sense_faders = string_is_affirmative (prop->value());
}
}
if ((child = node.child ("Buttons")) != 0) {
XMLNodeConstIterator i;
const XMLNodeList& nlist (child->children());
for (i = nlist.begin(); i != nlist.end(); ++i) {
if ((*i)->name() == "GlobalButton") {
if ((prop = (*i)->property ("name")) != 0) {
int id = Button::name_to_id (prop->value());
if (id >= 0) {
Button::ID bid = (Button::ID) id;
if ((prop = (*i)->property ("id")) != 0) {
int val = strtol (prop->value().c_str(), 0, 0);
std::map<Button::ID,GlobalButtonInfo>::iterator b = _global_buttons.find (bid);
if (b != _global_buttons.end()) {
b->second.id = val;
if ((prop = (*i)->property ("label")) != 0) {
b->second.label = prop->value();
}
}
}
}
}
} else if ((*i)->name() == "StripButton") {
if ((prop = (*i)->property ("name")) != 0) {
int id = Button::name_to_id (prop->value());
if (id >= 0) {
Button::ID bid = (Button::ID) id;
if ((prop = (*i)->property ("baseid")) != 0) {
int val = strtol (prop->value().c_str(), 0, 0);
std::map<Button::ID,StripButtonInfo>::iterator b = _strip_buttons.find (bid);
if (b != _strip_buttons.end()) {
b->second.base_id = val;
}
}
}
}
}
}
}
return 0;
}

View File

@ -25,10 +25,31 @@
#include <string>
#include <map>
#include "button.h"
class XMLNode;
namespace Mackie {
struct GlobalButtonInfo {
std::string label; // visible to user
std::string group; // in case we want to present in a GUI
int32_t id; // value sent by device
GlobalButtonInfo () : id (-1) {}
GlobalButtonInfo (const std::string& l, const std::string& g, uint32_t i)
: label (l), group (g), id (i) {}
};
struct StripButtonInfo {
int32_t base_id;
std::string name;
StripButtonInfo () : base_id (-1) {}
StripButtonInfo (uint32_t i, const std::string& n)
: base_id (i), name (n) {}
};
class DeviceInfo
{
public:
@ -51,6 +72,9 @@ class DeviceInfo
static std::map<std::string,DeviceInfo> device_info;
static void reload_device_info();
const std::map<Button::ID,GlobalButtonInfo>& global_buttons() const { return _global_buttons; }
const std::map<Button::ID,StripButtonInfo>& strip_buttons() const { return _strip_buttons; }
private:
uint32_t _strip_cnt;
uint32_t _extenders;
@ -62,6 +86,9 @@ class DeviceInfo
bool _has_jog_wheel;
bool _has_touch_sense_faders;
std::string _name;
std::map<Button::ID,GlobalButtonInfo> _global_buttons;
std::map<Button::ID,StripButtonInfo> _strip_buttons;
};
class DeviceProfile

View File

@ -20,7 +20,7 @@ class Fader : public Control
MidiByteArray update_message ();
static Control* factory (Surface&, int id, const char*, Group&);
private:
float position;
};

View File

@ -0,0 +1,36 @@
/*
Copyright (C) 2006,2007 John Anderson
Copyright (C) 2012 Paul Davis
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 "jog.h"
#include "surface.h"
#include "control_group.h"
using namespace Mackie;
const int Jog::ID = 0x3c;
Control*
Jog::factory (Surface& surface, int id, const char* name, Group& group)
{
Jog* j = new Jog (id, name, group);
surface.pots[id] = j;
surface.controls.push_back (j);
group.add (*j);
return j;
}

View File

@ -28,9 +28,7 @@ namespace Mackie {
class Jog : public Pot
{
public:
enum base_id_t {
base_id = 0x3c
};
static const int ID;
Jog (int id, std::string name, Group & group)
: Pot (id, name, group)

View File

@ -23,6 +23,12 @@
using namespace Mackie;
const int Led::FaderTouch = 0x70;
const int Led::Timecode = 0x71;
const int Led::Beats = 0x72;
const int Led::RudeSolo = 0x73;
const int Led::RelayClick = 0x74;
Control*
Led::factory (Surface& surface, int id, const char* name, Group& group)
{

View File

@ -29,6 +29,12 @@ namespace Mackie {
class Led : public Control
{
public:
static const int FaderTouch;
static const int Timecode;
static const int Beats;
static const int RudeSolo;
static const int RelayClick;
Led (int id, std::string name, Group & group)
: Control (id, name, group)
, state (off)

View File

@ -409,12 +409,12 @@ MackieControlProtocol::update_timecode_beats_led()
{
switch (_timecode_type) {
case ARDOUR::AnyTime::BBT:
update_global_led ("beats", on);
update_global_led ("timecode", off);
update_global_led (Led::Beats, on);
update_global_led (Led::Timecode, off);
break;
case ARDOUR::AnyTime::Timecode:
update_global_led ("timecode", on);
update_global_led ("beats", off);
update_global_led (Led::Timecode, on);
update_global_led (Led::Beats, off);
break;
default:
ostringstream os;
@ -424,7 +424,7 @@ MackieControlProtocol::update_timecode_beats_led()
}
void
MackieControlProtocol::update_global_button (const string & name, LedState ls)
MackieControlProtocol::update_global_button (int id, LedState ls)
{
boost::shared_ptr<Surface> surface = surfaces.front();
@ -432,16 +432,17 @@ MackieControlProtocol::update_global_button (const string & name, LedState ls)
return;
}
if (surface->controls_by_name.find (name) != surface->controls_by_name.end()) {
Button * button = dynamic_cast<Button*> (surface->controls_by_name[name]);
map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
if (x != surface->controls_by_device_independent_id.end()) {
Button * button = dynamic_cast<Button*> (x->second);
surface->write (button->set_state (ls));
} else {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Button %1 not found\n", name));
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Button %1 not found\n", id));
}
}
void
MackieControlProtocol::update_global_led (const string & name, LedState ls)
MackieControlProtocol::update_global_led (int id, LedState ls)
{
boost::shared_ptr<Surface> surface = surfaces.front();
@ -449,11 +450,12 @@ MackieControlProtocol::update_global_led (const string & name, LedState ls)
return;
}
if (surface->controls_by_name.find (name) != surface->controls_by_name.end()) {
Led * led = dynamic_cast<Led*> (surface->controls_by_name[name]);
map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (id);
if (x != surface->controls_by_device_independent_id.end()) {
Led * led = dynamic_cast<Led*> (x->second);
surface->write (led->set_state (ls));
} else {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Led %1 not found\n", name));
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Led %1 not found\n", id));
}
}
@ -755,11 +757,11 @@ MackieControlProtocol::update_timecode_display()
void MackieControlProtocol::notify_parameter_changed (std::string const & p)
{
if (p == "punch-in") {
update_global_button ("punch_in", session->config.get_punch_in());
update_global_button (Button::PunchIn, session->config.get_punch_in());
} else if (p == "punch-out") {
update_global_button ("punch_out", session->config.get_punch_out());
update_global_button (Button::PunchOut, session->config.get_punch_out());
} else if (p == "clicking") {
update_global_button ("clicking", Config->get_clicking());
// update_global_button (Button::RelayClick, Config->get_clicking());
} else {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("parameter changed: %1\n", p));
}
@ -789,10 +791,12 @@ MackieControlProtocol::notify_solo_active_changed (bool active)
{
boost::shared_ptr<Surface> surface = surfaces.front();
Led* rude_solo = dynamic_cast<Led*> (surface->controls_by_name["solo"]);
if (rude_solo) {
surface->write (rude_solo->set_state (active ? flashing : off));
map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Led::RudeSolo);
if (x != surface->controls_by_device_independent_id.end()) {
Led* rude_solo = dynamic_cast<Led*> (x->second);
if (rude_solo) {
surface->write (rude_solo->set_state (active ? flashing : off));
}
}
}
@ -821,17 +825,17 @@ MackieControlProtocol::notify_remote_id_changed()
void
MackieControlProtocol::notify_loop_state_changed()
{
update_global_button ("loop", session->get_play_loop());
update_global_button (Button::Loop, session->get_play_loop());
}
void
MackieControlProtocol::notify_transport_state_changed()
{
// switch various play and stop buttons on / off
update_global_button ("play", session->transport_speed() == 1.0);
update_global_button ("stop", !session->transport_rolling());
update_global_button ("rewind", session->transport_speed() < 0.0);
update_global_button ("ffwd", session->transport_speed() > 1.0);
update_global_button (Button::Play, session->transport_speed() == 1.0);
update_global_button (Button::Stop, !session->transport_rolling());
update_global_button (Button::Rewind, session->transport_speed() < 0.0);
update_global_button (Button::Ffwd, session->transport_speed() > 1.0);
_transport_previously_rolling = session->transport_rolling();
}
@ -839,31 +843,33 @@ MackieControlProtocol::notify_transport_state_changed()
void
MackieControlProtocol::notify_record_state_changed ()
{
boost::shared_ptr<Surface> surface = surfaces.front();
/* rec is a tristate */
Button * rec = reinterpret_cast<Button*> (surfaces.front()->controls_by_name["record"]);
if (rec) {
LedState ls;
switch (session->record_status()) {
case Session::Disabled:
DEBUG_TRACE (DEBUG::MackieControl, "record state changed to disabled, LED off\n");
ls = off;
break;
case Session::Recording:
DEBUG_TRACE (DEBUG::MackieControl, "record state changed to recording, LED on\n");
ls = on;
break;
case Session::Enabled:
DEBUG_TRACE (DEBUG::MackieControl, "record state changed to enabled, LED flashing\n");
ls = flashing;
break;
map<int,Control*>::iterator x = surface->controls_by_device_independent_id.find (Button::Record);
if (x != surface->controls_by_device_independent_id.end()) {
Button * rec = dynamic_cast<Button*> (x->second);
if (rec) {
LedState ls;
switch (session->record_status()) {
case Session::Disabled:
DEBUG_TRACE (DEBUG::MackieControl, "record state changed to disabled, LED off\n");
ls = off;
break;
case Session::Recording:
DEBUG_TRACE (DEBUG::MackieControl, "record state changed to recording, LED on\n");
ls = on;
break;
case Session::Enabled:
DEBUG_TRACE (DEBUG::MackieControl, "record state changed to enabled, LED flashing\n");
ls = flashing;
break;
}
surface->write (rec->set_state (ls));
}
surfaces.front()->write (rec->set_state (ls));
} else {
DEBUG_TRACE (DEBUG::MackieControl, "record button control not found\n");
}
}
@ -969,9 +975,9 @@ MackieControlProtocol::update_led (Surface& surface, Button& button, Mackie::Led
void
MackieControlProtocol::build_button_map ()
{
#define DEFINE_BUTTON_HANDLER(b,p,r) button_map.insert (pair<int,ButtonHandlers> ((b), ButtonHandlers ((p),(r))));
#define DEFINE_BUTTON_HANDLER(b,p,r) button_map.insert (pair<Button::ID,ButtonHandlers> ((b), ButtonHandlers ((p),(r))));
DEFINE_BUTTON_HANDLER (Button::Io, &MackieControlProtocol::io_press, &MackieControlProtocol::io_release);
DEFINE_BUTTON_HANDLER (Button::IO, &MackieControlProtocol::io_press, &MackieControlProtocol::io_release);
DEFINE_BUTTON_HANDLER (Button::Sends, &MackieControlProtocol::sends_press, &MackieControlProtocol::sends_release);
DEFINE_BUTTON_HANDLER (Button::Pan, &MackieControlProtocol::pan_press, &MackieControlProtocol::pan_release);
DEFINE_BUTTON_HANDLER (Button::Plugin, &MackieControlProtocol::plugin_press, &MackieControlProtocol::plugin_release);
@ -1047,7 +1053,9 @@ MackieControlProtocol::handle_button_event (Surface& surface, Button& button, Bu
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Handling %1 for button %2\n", (bs == press ? "press" : "release"), button.id()));
ButtonMap::iterator b = button_map.find (button.id());
/* lookup using the device-INDEPENDENT button ID */
ButtonMap::iterator b = button_map.find (button.bid());
if (b != button_map.end()) {

View File

@ -171,8 +171,8 @@ class MackieControlProtocol
/// this is called to generate the midi to send in response to a button press.
void update_led(Mackie::Surface&, Mackie::Button & button, Mackie::LedState);
void update_global_button(const std::string & name, Mackie::LedState);
void update_global_led(const std::string & name, Mackie::LedState);
void update_global_button (int id, Mackie::LedState);
void update_global_led (int id, Mackie::LedState);
ARDOUR::Session & get_session() { return *session; }
framepos_t transport_frame() const;
@ -247,7 +247,7 @@ class MackieControlProtocol
, release (r) {}
};
typedef std::map<int,ButtonHandlers> ButtonMap;
typedef std::map<Mackie::Button::ID,ButtonHandlers> ButtonMap;
typedef std::list<GSource*> PortSources;
static MackieControlProtocol* _instance;

View File

@ -24,6 +24,8 @@
using namespace Mackie;
int const Pot::External = 0x2e;
Control*
Pot::factory (Surface& surface, int id, const char* name, Group& group)
{

View File

@ -27,9 +27,7 @@ namespace Mackie {
class Pot : public Control
{
public:
enum base_id_t {
base_id = 0x10,
};
static int const External;
enum Mode {
dot = 0,

View File

@ -59,7 +59,7 @@ using namespace PBD;
extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
#define invalidator() __invalidator (*(MackieControlProtocol::instance()), __FILE__, __LINE__)
Strip::Strip (Surface& s, const std::string& name, int index, StripControlDefinition* ctls)
Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
: Group (name)
, _solo (0)
, _recenable (0)
@ -76,75 +76,51 @@ Strip::Strip (Surface& s, const std::string& name, int index, StripControlDefini
, _last_gain_position_written (-1.0)
, _last_pan_position_written (-1.0)
{
/* build the controls for this track, which will automatically add them
to the Group
*/
_fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
_vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, index, "vpot", *this));
_meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
for (uint32_t i = 0; ctls[i].name[0]; ++i) {
ctls[i].factory (*_surface, ctls[i].base_id + index, ctls[i].name, *this);
for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
(void) Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this);
}
}
Strip::~Strip ()
{
/* surface is responsible for deleting all controls */
}
/**
TODO could optimise this to use enum, but it's only
called during the protocol class instantiation.
*/
void Strip::add (Control & control)
void
Strip::add (Control & control)
{
Button* button;
Group::add (control);
Fader* fader;
Pot* pot;
Button* button;
Meter* meter;
/* fader, vpot, meter were all set explicitly */
if ((fader = dynamic_cast<Fader*>(&control)) != 0) {
_fader = fader;
} else if ((pot = dynamic_cast<Pot*>(&control)) != 0) {
_vpot = pot;
} else if ((button = dynamic_cast<Button*>(&control)) != 0) {
if (control.id() >= Button::recenable_base_id &&
control.id() < Button::recenable_base_id + 8) {
if ((button = dynamic_cast<Button*>(&control)) != 0) {
switch (button->bid()) {
case Button::RecEnable:
_recenable = button;
} else if (control.id() >= Button::mute_base_id &&
control.id() < Button::mute_base_id + 8) {
break;
case Button::Mute:
_mute = button;
} else if (control.id() >= Button::solo_base_id &&
control.id() < Button::solo_base_id + 8) {
break;
case Button::Solo:
_solo = button;
} else if (control.id() >= Button::select_base_id &&
control.id() < Button::select_base_id + 8) {
break;
case Button::Select:
_select = button;
} else if (control.id() >= Button::vselect_base_id &&
control.id() < Button::vselect_base_id + 8) {
break;
case Button::VSelect:
_vselect = button;
} else if (control.id() >= Button::fader_touch_base_id &&
control.id() < Button::fader_touch_base_id + 8) {
break;
case Button::FaderTouch:
_fader_touch = button;
default:
break;
}
} else if ((meter = dynamic_cast<Meter*>(&control)) != 0) {
_meter = meter;
}
}
@ -385,14 +361,13 @@ Strip::handle_button (Button& button, ButtonState bs)
button.set_in_use (false);
}
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.id(), (bs == press)));
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
int lock_mod = (MackieControlProtocol::MODIFIER_CONTROL|MackieControlProtocol::MODIFIER_SHIFT);
int ms = _surface->mcp().modifier_state();
bool modified = (ms & MackieControlProtocol::MODIFIER_CONTROL);
if (button.id() >= Button::select_base_id &&
button.id() < Button::select_base_id + 8) {
if (button.bid() == Button::Select) {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("select touch, lock ? %1\n", ((ms & lock_mod) == lock_mod) ? 1 : 0));
@ -415,9 +390,8 @@ Strip::handle_button (Button& button, ButtonState bs)
return;
}
if ((button.id() >= Button::fader_touch_base_id &&
button.id() < Button::fader_touch_base_id + 8)) {
if (button.bid() == Button::FaderTouch) {
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("fader touch, press ? %1\n", (bs == press)));

View File

@ -13,6 +13,7 @@
#include "control_group.h"
#include "types.h"
#include "midi_byte_array.h"
#include "device_info.h"
namespace ARDOUR {
class Route;
@ -47,7 +48,7 @@ struct GlobalControlDefinition {
class Strip : public Group
{
public:
Strip (Surface&, const std::string & name, int index, StripControlDefinition* ctls);
Strip (Surface&, const std::string & name, int index, const std::map<Button::ID,StripButtonInfo>&);
~Strip();
boost::shared_ptr<ARDOUR::Route> route() const { return _route; }

View File

@ -50,81 +50,6 @@ static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x15)
static MidiByteArray empty_midi_byte_array;
static GlobalControlDefinition mackie_global_controls[] = {
{ "jog", 0x3c, Jog::factory, "none" },
{ "external", 0x2e, Pot::factory, "none" },
{ "io", 0x28, Button::factory, "assignment" },
{ "sends", 0x29, Button::factory, "assignment" },
{ "pan", 0x2a, Button::factory, "assignment" },
{ "plugin", 0x2b, Button::factory, "assignment" },
{ "eq", 0x2c, Button::factory, "assignment" },
{ "dyn", 0x2d, Button::factory, "assignment" },
{ "left", 0x2e, Button::factory, "bank" },
{ "right", 0x2f, Button::factory, "bank" },
{ "channel_left", 0x30, Button::factory, "bank" },
{ "channel_right", 0x31, Button::factory, "bank" },
{ "flip", 0x32, Button::factory, "none" },
{ "edit", 0x33, Button::factory, "none" },
{ "name_value", 0x34, Button::factory, "display" },
{ "timecode_beats", 0x35, Button::factory, "display" },
{ "F1", Button::F1, Button::factory, "none" },
{ "F2", Button::F2, Button::factory, "none" },
{ "F3", Button::F3, Button::factory, "none" },
{ "F4", Button::F4, Button::factory, "none" },
{ "F5", Button::F5, Button::factory, "none" },
{ "F6", Button::F6, Button::factory, "none" },
{ "F7", Button::F7, Button::factory, "none" },
{ "F8", Button::F8, Button::factory, "none" },
{ "F9", Button::F9, Button::factory, "none" },
{ "F10", Button::F10, Button::factory, "none" },
{ "F11", Button::F11, Button::factory, "none" },
{ "F12", Button::F12, Button::factory, "none" },
{ "F13", Button::F13, Button::factory, "none" },
{ "F14", Button::F14, Button::factory, "none" },
{ "F15", Button::F15, Button::factory, "none" },
{ "F16", Button::F16, Button::factory, "none" },
{ "shift", 0x46, Button::factory, "modifiers" },
{ "option", 0x47, Button::factory, "modifiers" },
{ "control", 0x48, Button::factory, "modifiers" },
{ "cmd_alt", 0x49, Button::factory, "modifiers" },
{ "on", 0x4a, Button::factory, "automation" },
{ "rec_ready", 0x4b, Button::factory, "automation" },
{ "undo", 0x4c, Button::factory, "functions" },
{ "save", Button::Save, Button::factory, "automation" },
{ "touch", Button::Touch, Button::factory, "automation" },
{ "redo", Button::Redo, Button::factory, "functions" },
{ "marker", Button::Marker, Button::factory, "functions" },
{ "enter", Button::Enter, Button::factory, "functions" },
{ "cancel", Button::Cancel, Button::factory, "functions" },
{ "mixer", Button::Mixer, Button::factory, "functions" },
{ "frm_left", 0x54, Button::factory, "transport" },
{ "frm_right", 0x55, Button::factory, "transport" },
{ "loop", Button::Loop, Button::factory, "transport" },
{ "punch_in", 0x57, Button::factory, "transport" },
{ "punch_out", 0x58, Button::factory, "transport" },
{ "home", Button::Home, Button::factory, "transport" },
{ "end", Button::End, Button::factory, "transport" },
{ "rewind", Button::Rewind, Button::factory, "transport" },
{ "ffwd", Button::Ffwd, Button::factory, "transport" },
{ "stop", Button::Stop, Button::factory, "transport" },
{ "play", Button::Play, Button::factory, "transport" },
{ "record", Button::Record, Button::factory, "transport" },
{ "cursor_up", Button::CursorUp, Button::factory, "cursor" },
{ "cursor_down", Button::CursorDown, Button::factory, "cursor" },
{ "cursor_left", Button::CursorLeft, Button::factory, "cursor" },
{ "cursor_right", Button::CursorRight, Button::factory, "cursor" },
{ "zoom", Button::Zoom, Button::factory, "none" },
{ "scrub", Button::Scrub, Button::factory, "none" },
{ "user_a", Button::UserA, Button::factory, "user" },
{ "user_b", Button::UserB, Button::factory, "user" },
{ "fader_touch", 0x70, Led::factory, "master" },
{ "timecode", 0x71, Led::factory, "none" },
{ "beats", 0x72, Led::factory, "none" },
{ "solo", 0x73, Led::factory, "none" },
{ "relay_click", 0x73, Led::factory, "none" },
{ "", 0, Button::factory, "" }
};
Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, uint32_t number, surface_type_t stype)
: _mcp (mcp)
, _stype (stype)
@ -138,12 +63,12 @@ Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, ui
_port = new SurfacePort (*this);
if (_mcp.device_info().has_global_controls()) {
init_controls ();
}
/* only the first Surface object has global controls */
if (_mcp.device_info().has_jog_wheel()) {
_jog_wheel = new Mackie::JogWheel (_mcp);
if (_number == 0) {
if (_mcp.device_info().has_global_controls()) {
init_controls ();
}
}
uint32_t n = _mcp.device_info().strip_cnt();
@ -204,6 +129,16 @@ Surface::sysex_hdr() const
return mackie_sysex_hdr;
}
static GlobalControlDefinition mackie_global_controls[] = {
{ "external", Pot::External, Pot::factory, "none" },
{ "fader_touch", Led::FaderTouch, Led::factory, "master" },
{ "timecode", Led::Timecode, Led::factory, "none" },
{ "beats", Led::Beats, Led::factory, "none" },
{ "solo", Led::RudeSolo, Led::factory, "none" },
{ "relay_click", Led::RelayClick, Led::factory, "none" },
{ "", 0, Led::factory, "" }
};
void
Surface::init_controls()
{
@ -220,38 +155,39 @@ Surface::init_controls()
groups["transport"] = new Group ("transport");
groups["user"] = new Group ("user");
groups["master"] = new Group ("master");
if (_mcp.device_info().has_jog_wheel()) {
_jog_wheel = new Mackie::JogWheel (_mcp);
}
for (uint32_t n = 0; mackie_global_controls[n].name[0]; ++n) {
group = groups[mackie_global_controls[n].group_name];
Control* control = mackie_global_controls[n].factory (*this, mackie_global_controls[n].id, mackie_global_controls[n].name, *group);
controls_by_name[mackie_global_controls[n].name] = control;
group->add (*control);
controls_by_device_independent_id[mackie_global_controls[n].id] = control;
}
/* add global buttons */
const map<Button::ID,GlobalButtonInfo>& global_buttons (_mcp.device_info().global_buttons());
for (map<Button::ID,GlobalButtonInfo>::const_iterator b = global_buttons.begin(); b != global_buttons.end(); ++b){
group = groups[b->second.group];
controls_by_device_independent_id[b->first] = Button::factory (*this, b->first, b->second.id, b->second.label, *group);
}
}
static StripControlDefinition mackie_strip_controls[] = {
{ "gain", 0, Fader::factory, },
{ "vpot", Pot::base_id, Pot::factory, },
{ "recenable", Button::recenable_base_id, Button::factory, },
{ "solo", Button::solo_base_id, Button::factory, },
{ "mute", Button::mute_base_id, Button::factory, },
{ "select", Button::select_base_id, Button::factory, },
{ "vselect", Button::vselect_base_id, Button::factory, },
{ "fader_touch", Button::fader_touch_base_id, Button::factory, },
{ "meter", 0, Meter::factory, },
{ "", 0, Button::factory, }
};
void
Surface::init_strips (uint32_t n)
{
const map<Button::ID,StripButtonInfo>& strip_buttons (_mcp.device_info().strip_buttons());
for (uint32_t i = 0; i < n; ++i) {
char name[32];
snprintf (name, sizeof (name), "strip_%d", (8* _number) + i);
Strip* strip = new Strip (*this, name, i, mackie_strip_controls);
Strip* strip = new Strip (*this, name, i, strip_buttons);
groups[name] = strip;
strips.push_back (strip);
@ -280,7 +216,7 @@ Surface::display_bank_start (uint32_t current_bank)
void
Surface::blank_jog_ring ()
{
Control* control = controls_by_name["jog"];
Control* control = controls_by_device_independent_id[Jog::ID];
if (control) {
Pot* pot = dynamic_cast<Pot*> (control);
@ -395,10 +331,6 @@ Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev
Pot* pot = pots[ev->controller_number];
if (!pot && ev->controller_number == Jog::base_id) {
pot = dynamic_cast<Pot*> (controls_by_name["jog"]);
}
if (pot) {
ControlState state;

View File

@ -53,13 +53,10 @@ public:
std::map<int,Fader*> faders;
std::map<int,Pot*> pots;
std::map<int,Button*> buttons;
std::map<int,Button*> buttons; // index is device-DEPENDENT
std::map<int,Led*> leds;
std::map<int,Meter*> meters;
/// no strip controls in here because they usually
/// have the same names.
std::map<std::string,Control*> controls_by_name;
std::map<int,Control*> controls_by_device_independent_id;
Mackie::JogWheel* jog_wheel() const { return _jog_wheel; }

View File

@ -27,6 +27,7 @@ def build(bld):
fader.cc
gui.cc
interface.cc
jog.cc
led.cc
mackie_control_protocol.cc
mackie_jog_wheel.cc

View File

@ -2,12 +2,20 @@
<MackieProtocolDevice>
<Name value="SSL Nucleus"/>
<Strips value="8"/>
<Extenders value="1"/>
<MasterFader value="no"/>
<SegmentedDisplay value="yes"/>
<TimecodeDisplay value="no"/>
<TwoCharacterDisplay value="yes"/>
<Extenders value="1"/>
<GlobalControls value="yes"/>
<JogWheel value="no"/>
<JogWheel value="yes"/>
<TouchSenseFaders value="yes"/>
<SendsModifiers value="0x3"/>
<Quirks>
<ButtonOffNonZero/>
</Quirks>
<Buttons>
<GlobalButton name="Marker" id="0x48" label="instrument"/>
<StripButton name="FaderTouch" baseid="0x68"/>
</Buttons>
</MackieProtocolDevice>