summaryrefslogtreecommitdiff
path: root/libs/surfaces
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2008-12-12 22:55:03 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2008-12-12 22:55:03 +0000
commit51625b2474e72850d19ff521d1b9f80be8b24136 (patch)
treea26983d5e3fdd437fa227ebcb0e188bc72a20e90 /libs/surfaces
parentf03a87a132feb525a743de675d0439e981ab329a (diff)
"merge" (i.e. wholesale import) 2.0-ongoing Mackie code and then fix to compile in 3.0 context
git-svn-id: svn://localhost/ardour2/branches/3.0@4315 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/surfaces')
-rw-r--r--libs/surfaces/mackie/README18
-rw-r--r--libs/surfaces/mackie/SConscript17
-rw-r--r--libs/surfaces/mackie/TODO67
-rw-r--r--libs/surfaces/mackie/bcf_surface.cc1457
-rw-r--r--libs/surfaces/mackie/bcf_surface.h11
-rw-r--r--libs/surfaces/mackie/bcf_surface_generated.cc1461
-rw-r--r--libs/surfaces/mackie/controls.cc125
-rw-r--r--libs/surfaces/mackie/controls.h91
-rw-r--r--libs/surfaces/mackie/dummy_port.cc58
-rw-r--r--libs/surfaces/mackie/dummy_port.h60
-rw-r--r--libs/surfaces/mackie/interface.cc21
-rw-r--r--libs/surfaces/mackie/mackie_button_handler.cc20
-rw-r--r--libs/surfaces/mackie/mackie_button_handler.h6
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc770
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h70
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol_poll.cc60
-rw-r--r--libs/surfaces/mackie/mackie_jog_wheel.cc194
-rw-r--r--libs/surfaces/mackie/mackie_jog_wheel.h102
-rw-r--r--libs/surfaces/mackie/mackie_midi_builder.cc117
-rw-r--r--libs/surfaces/mackie/mackie_midi_builder.h35
-rw-r--r--libs/surfaces/mackie/mackie_port.cc324
-rw-r--r--libs/surfaces/mackie/mackie_port.h14
-rw-r--r--libs/surfaces/mackie/mackie_surface.cc1502
-rw-r--r--libs/surfaces/mackie/mackie_surface.h7
-rw-r--r--libs/surfaces/mackie/mackie_surface_generated.cc1507
-rw-r--r--libs/surfaces/mackie/midi_byte_array.cc10
-rw-r--r--libs/surfaces/mackie/midi_byte_array.h3
-rw-r--r--libs/surfaces/mackie/route_signal.cc45
-rw-r--r--libs/surfaces/mackie/route_signal.h33
-rw-r--r--libs/surfaces/mackie/scripts/bcf-controls.csv13
-rw-r--r--libs/surfaces/mackie/scripts/controls.rb10
-rwxr-xr-xlibs/surfaces/mackie/scripts/host.rb45
-rw-r--r--libs/surfaces/mackie/scripts/mackie-dump.midibin0 -> 495 bytes
-rw-r--r--libs/surfaces/mackie/scripts/simple_host.rb15
-rw-r--r--libs/surfaces/mackie/scripts/surface-cc-template.erb26
-rwxr-xr-xlibs/surfaces/mackie/scripts/test_controls.rb2
-rw-r--r--libs/surfaces/mackie/surface.cc86
-rw-r--r--libs/surfaces/mackie/surface.h43
-rw-r--r--libs/surfaces/mackie/surface_port.cc65
-rw-r--r--libs/surfaces/mackie/surface_port.h16
-rw-r--r--libs/surfaces/mackie/timer.h136
-rw-r--r--libs/surfaces/mackie/types.cc28
-rw-r--r--libs/surfaces/mackie/types.h19
43 files changed, 5092 insertions, 3617 deletions
diff --git a/libs/surfaces/mackie/README b/libs/surfaces/mackie/README
new file mode 100644
index 0000000000..5ed3a75fa5
--- /dev/null
+++ b/libs/surfaces/mackie/README
@@ -0,0 +1,18 @@
+For usage, see
+
+http://www.ardour.org/files/manual/sn-mackie.html
+
+unfortunately it's a bit outdated, so to get the latest manual, go to the manual
+directory in the ardour source tree, and say "make html" to build the latest.
+Then point your favourite browser at tmp/index.html
+
+NOTES:
+
+* support for alsa/sequencer ports is currently broken. We're working on it.
+
+* you'll need to make port changes in etc/ardour2/ardour_system.rc and
+etc/ardour2/ardour.rc, otherwise they don't stay changed in ~/.ardour2/ardour.rc
+
+
+John Anderson
+panic@semiosix.com
diff --git a/libs/surfaces/mackie/SConscript b/libs/surfaces/mackie/SConscript
index c19d145c73..96b37c2d6e 100644
--- a/libs/surfaces/mackie/SConscript
+++ b/libs/surfaces/mackie/SConscript
@@ -14,12 +14,16 @@ mackie = env.Clone()
domain = 'ardour_mackie'
-mackie.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+mackie.Append(DOMAIN = domain, MAJOR = 1, MINOR = 1, MICRO = 0)
mackie.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
mackie.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
mackie.Append(PACKAGE = domain)
mackie.Append(POTFILE = domain + '.pot')
+if mackie['DEBUG'] == 1:
+ mackie.Append(CXXFLAGS="-DDEBUG")
+ mackie.Append(CXXFLAGS="-DPORT_DEBUG")
+
if mackie['IS_OSX']:
mackie.Append (LINKFLAGS="-Xlinker -headerpad -Xlinker 2048")
@@ -27,17 +31,21 @@ mackie_files=Split("""
interface.cc
midi_byte_array.cc
controls.cc
+surface_port.cc
+dummy_port.cc
+mackie_port.cc
route_signal.cc
mackie_midi_builder.cc
mackie_button_handler.cc
mackie_control_protocol_poll.cc
-surface_port.cc
-mackie_port.cc
types.cc
surface.cc
mackie_control_protocol.cc
bcf_surface.cc
+bcf_surface_generated.cc
mackie_surface.cc
+mackie_surface_generated.cc
+mackie_jog_wheel.cc
""")
mackie.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
@@ -53,7 +61,6 @@ mackie.Merge ([
libraries['sigc2'],
libraries['pbd'],
libraries['midi++2'],
- libraries['evoral'],
libraries['xml'],
libraries['glib2'],
libraries['glibmm2'],
@@ -72,7 +79,7 @@ if mackie['SURFACES']:
Default(libardour_mackie)
if env['NLS']:
i18n (mackie, mackie_files, env)
- env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour3','surfaces'), libardour_mackie))
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2','surfaces'), libardour_mackie))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript' ] +
diff --git a/libs/surfaces/mackie/TODO b/libs/surfaces/mackie/TODO
index a9cb1b9878..2573e0f05b 100644
--- a/libs/surfaces/mackie/TODO
+++ b/libs/surfaces/mackie/TODO
@@ -1,20 +1,48 @@
-* how long can UI signal callbacks take to execute? What happens if they block?
- where ENSURE_CORRECT_THREAD is a macro that is modelled on ENSURE_GUI_THREAD
- if the handler is not called in the "correct thread", it will use a pseudo-RT-safe-enough technique to get the correct thread to recall "handler" later on, and return.
-
-* jog with transport rolling doesn't work properly. My use of ScrollTimeline also doesn't work.
-* make loop button sensitive to current transport state
-* make sure rew button can go past the previous if pressed twice, relatively quickly.
-* finish button mapping. Only shifted buttons left for bcf.
+* implement handle_port_inactive properly
+* two bcf doesn't work
+* remappable buttons (OSC or Surfax?)
+* 7/1 configurable to 8
+* need an object that can encapsulate different port types, ie BCF vs MCU. Not at the surface level.
+* finish button implementations.
* concurrency for bank switching? And make sure "old" events aren't sent to "new" faders
* TODOs in code
* removal of a route results in a strip that isn't dead, but doesn't have any effect on the session
* use i18n. see string_compose
-* docs in manual, including button assignment diagram
+
+MCU
+---
+* if mackie wheel moves too fast, it's ignored.
+* gain/panner display in second line
+* metering on second line
+* per-strip signal led
+* midi bandwidth?
+* Zoom buttons, from Jean-Martin Barbut. In fact I'm a bit desappointed with those functions, because I was used
+ to use the 4 "N-E-S-W" buttons to zoom in and out with horizontal
+ buttons and zoom in/out on track height with vertical buttons. That is
+ with the zoom button in. with the zoom button off, it selects tracks
+ with vertical buttons and selects regions with horizontal buttons. This
+ was quite useful. The fact that the zoom button switches the wheel to
+ zoom is fine, but it would be great to also have the track/region
+ selection and the track height available from those buttons. I.e : you
+ select a track with the vertical arrows and you increase/decrease the
+ eight of the track with the zoom btn on. This combined with the region
+ selection allows to zoom in a region (vertical and horizontal zoom) very
+ easily.
+
Later
-----
+* how long can UI signal callbacks take to execute? What happens if they block?
+ where ENSURE_CORRECT_THREAD is a macro that is modelled on ENSURE_GUI_THREAD
+ if the handler is not called in the "correct thread", it will use a pseudo-RT-safe-enough technique to get the correct thread to recall "handler" later on, and return.
+* alsa/sequencer ports unstable. possibly problems with use of ::poll
+* use glib::Timer instead of mine. Actually don't because it's not very useable.
+* crash when mmc port set to mcu?
* remove commented couts
+* Perhaps MackieControlProtocol shouldn't implement MackieButtonHandler
+* Need a HostAdapter class to encapsulate ardour calls
+* talk to route plugins
+* check for excessiveness (ie too many events making other subsystems work too hard)
* Queueing of writes?
* Generic surface code to common location
* bulk remote id changes cause too many surface updates. use Config->remote_model.
@@ -25,21 +53,16 @@ Later
* mix busses and/or a "bus-only" bank/mode
* what about surfaces like Mackie C4 and BCR2000?
-Need UI integration
--------------------
+UI integration
+--------------
+
+* maybe use current snap state for jog wheel and ffwd/rew
* Some indication on the UI of currently bank-switched-in routes?
Useful for surfaces that don't have a scribble strip.
-* use current zoom setting and snap state for shuttle wheel
-
-Actual Mackie
--------------
-* docs claim that unit will send a host query on init.
-* test Mackie surface object. Apparently led rings don't work. Stereo busses?
-* timecode & 55 char displays
-* midi bandwidth
Bugs
----
-
-* definitely something wrong with remote_id assignment on session create
- (master strip assigned 0).
+* when using alsa/sequencer, some midi events intended for mcu port end up being
+ read by the seq port.
+* MIDI::Port::type() returns _type, which is undefined. It might be in the descriptor
+* auditioner doesn't connect to master 1 and master 2 - it loses the spaces.
diff --git a/libs/surfaces/mackie/bcf_surface.cc b/libs/surfaces/mackie/bcf_surface.cc
index 45b5ad85fa..0898e95ba1 100644
--- a/libs/surfaces/mackie/bcf_surface.cc
+++ b/libs/surfaces/mackie/bcf_surface.cc
@@ -1,1443 +1,42 @@
-/*
- Generated by scripts/generate-surface.rb
-*/
-
#include "bcf_surface.h"
+#include "surface_port.h"
+#include "mackie_midi_builder.h"
-#include "controls.h"
-#include "mackie_button_handler.h"
+#include <cmath>
using namespace Mackie;
-void Mackie::BcfSurface::init_controls()
+void BcfSurface::display_bank_start( SurfacePort & port, MackieMidiBuilder & builder, uint32_t current_bank )
{
- // intialise groups and strips
- Group * group = 0;
-
- // make sure there are enough strips
- strips.resize( 7 );
-
- group = new Group ( "user" );
- groups["user"] = group;
-
- group = new Group ( "assignment" );
- groups["assignment"] = group;
-
- group = new Group ( "none" );
- groups["none"] = group;
-
- group = new MasterStrip ( "master", 0 );
- groups["master"] = group;
- strips[0] = dynamic_cast<Strip*>( group );
-
- group = new Strip ( "strip_1", 0 );
- groups["strip_1"] = group;
- strips[0] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "cursor" );
- groups["cursor"] = group;
-
- group = new Strip ( "strip_2", 1 );
- groups["strip_2"] = group;
- strips[1] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "functions" );
- groups["functions"] = group;
-
- group = new Group ( "automation" );
- groups["automation"] = group;
-
- group = new Strip ( "strip_3", 2 );
- groups["strip_3"] = group;
- strips[2] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "display" );
- groups["display"] = group;
-
- group = new Strip ( "strip_4", 3 );
- groups["strip_4"] = group;
- strips[3] = dynamic_cast<Strip*>( group );
-
- group = new Strip ( "strip_5", 4 );
- groups["strip_5"] = group;
- strips[4] = dynamic_cast<Strip*>( group );
-
- group = new Strip ( "strip_6", 5 );
- groups["strip_6"] = group;
- strips[5] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "transport" );
- groups["transport"] = group;
-
- group = new Strip ( "strip_7", 6 );
- groups["strip_7"] = group;
- strips[6] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "modifiers" );
- groups["modifiers"] = group;
-
- group = new Group ( "bank" );
- groups["bank"] = group;
-
-
- // initialise controls
- Control * control = 0;
-
- group = groups["strip_1"];
- control = new Fader ( 0, 1, "gain", *group );
- faders[0x00] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Fader ( 1, 2, "gain", *group );
- faders[0x01] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Fader ( 2, 3, "gain", *group );
- faders[0x02] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Fader ( 3, 4, "gain", *group );
- faders[0x03] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Fader ( 4, 5, "gain", *group );
- faders[0x04] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Fader ( 5, 6, "gain", *group );
- faders[0x05] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Fader ( 6, 7, "gain", *group );
- faders[0x06] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["master"];
- control = new Fader ( 7, 1, "gain", *group );
- faders[0x07] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Pot ( 16, 1, "vpot", *group );
- pots[0x10] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Pot ( 17, 2, "vpot", *group );
- pots[0x11] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Pot ( 18, 3, "vpot", *group );
- pots[0x12] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Pot ( 19, 4, "vpot", *group );
- pots[0x13] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Pot ( 20, 5, "vpot", *group );
- pots[0x14] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Pot ( 21, 6, "vpot", *group );
- pots[0x15] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Pot ( 22, 7, "vpot", *group );
- pots[0x16] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["none"];
- control = new Pot ( 23, 1, "jog", *group );
- pots[0x17] = control;
- controls.push_back( control );
- controls_by_name["jog"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Pot ( 46, 1, "external", *group );
- pots[0x2e] = control;
- controls.push_back( control );
- controls_by_name["external"] = control;
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 24, 1, "recenable", *group );
- buttons[0x18] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 25, 2, "recenable", *group );
- buttons[0x19] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 26, 3, "recenable", *group );
- buttons[0x1a] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 27, 4, "recenable", *group );
- buttons[0x1b] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 28, 5, "recenable", *group );
- buttons[0x1c] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 29, 6, "recenable", *group );
- buttons[0x1d] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 30, 7, "recenable", *group );
- buttons[0x1e] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 32, 1, "solo", *group );
- buttons[0x20] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 33, 2, "solo", *group );
- buttons[0x21] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 34, 3, "solo", *group );
- buttons[0x22] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 35, 4, "solo", *group );
- buttons[0x23] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 36, 5, "solo", *group );
- buttons[0x24] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 37, 6, "solo", *group );
- buttons[0x25] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 38, 7, "solo", *group );
- buttons[0x26] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 16, 1, "mute", *group );
- buttons[0x10] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 17, 2, "mute", *group );
- buttons[0x11] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 18, 3, "mute", *group );
- buttons[0x12] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 19, 4, "mute", *group );
- buttons[0x13] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 20, 5, "mute", *group );
- buttons[0x14] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 21, 6, "mute", *group );
- buttons[0x15] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 22, 7, "mute", *group );
- buttons[0x16] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 0, 1, "select", *group );
- buttons[0x00] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 1, 2, "select", *group );
- buttons[0x01] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 2, 3, "select", *group );
- buttons[0x02] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 3, 4, "select", *group );
- buttons[0x03] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 4, 5, "select", *group );
- buttons[0x04] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 5, 6, "select", *group );
- buttons[0x05] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 6, 7, "select", *group );
- buttons[0x06] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 8, 1, "vselect", *group );
- buttons[0x08] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 9, 2, "vselect", *group );
- buttons[0x09] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 10, 3, "vselect", *group );
- buttons[0x0a] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 11, 4, "vselect", *group );
- buttons[0x0b] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 12, 5, "vselect", *group );
- buttons[0x0c] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 13, 6, "vselect", *group );
- buttons[0x0d] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 14, 7, "vselect", *group );
- buttons[0x0e] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 40, 1, "io", *group );
- buttons[0x28] = control;
- controls.push_back( control );
- controls_by_name["io"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 90, 1, "sends", *group );
- buttons[0x5a] = control;
- controls.push_back( control );
- controls_by_name["sends"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 89, 1, "pan", *group );
- buttons[0x59] = control;
- controls.push_back( control );
- controls_by_name["pan"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 87, 1, "plugin", *group );
- buttons[0x57] = control;
- controls.push_back( control );
- controls_by_name["plugin"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 88, 1, "eq", *group );
- buttons[0x58] = control;
- controls.push_back( control );
- controls_by_name["eq"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 45, 1, "dyn", *group );
- buttons[0x2d] = control;
- controls.push_back( control );
- controls_by_name["dyn"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 46, 1, "left", *group );
- buttons[0x2e] = control;
- controls.push_back( control );
- controls_by_name["left"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 47, 1, "right", *group );
- buttons[0x2f] = control;
- controls.push_back( control );
- controls_by_name["right"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 48, 1, "channel_left", *group );
- buttons[0x30] = control;
- controls.push_back( control );
- controls_by_name["channel_left"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 49, 1, "channel_right", *group );
- buttons[0x31] = control;
- controls.push_back( control );
- controls_by_name["channel_right"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 50, 1, "flip", *group );
- buttons[0x32] = control;
- controls.push_back( control );
- controls_by_name["flip"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 86, 1, "edit", *group );
- buttons[0x56] = control;
- controls.push_back( control );
- controls_by_name["edit"] = control;
- group->add( *control );
-
- group = groups["display"];
- control = new Button ( 52, 1, "name_value", *group );
- buttons[0x34] = control;
- controls.push_back( control );
- controls_by_name["name_value"] = control;
- group->add( *control );
-
- group = groups["display"];
- control = new Button ( 53, 1, "smpte_beats", *group );
- buttons[0x35] = control;
- controls.push_back( control );
- controls_by_name["smpte_beats"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 54, 1, "F1", *group );
- buttons[0x36] = control;
- controls.push_back( control );
- controls_by_name["F1"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 55, 1, "F2", *group );
- buttons[0x37] = control;
- controls.push_back( control );
- controls_by_name["F2"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 56, 1, "F3", *group );
- buttons[0x38] = control;
- controls.push_back( control );
- controls_by_name["F3"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 57, 1, "F4", *group );
- buttons[0x39] = control;
- controls.push_back( control );
- controls_by_name["F4"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 58, 1, "F5", *group );
- buttons[0x3a] = control;
- controls.push_back( control );
- controls_by_name["F5"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 59, 1, "F6", *group );
- buttons[0x3b] = control;
- controls.push_back( control );
- controls_by_name["F6"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 60, 1, "F7", *group );
- buttons[0x3c] = control;
- controls.push_back( control );
- controls_by_name["F7"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 61, 1, "F8", *group );
- buttons[0x3d] = control;
- controls.push_back( control );
- controls_by_name["F8"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 62, 1, "F9", *group );
- buttons[0x3e] = control;
- controls.push_back( control );
- controls_by_name["F9"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 63, 1, "F10", *group );
- buttons[0x3f] = control;
- controls.push_back( control );
- controls_by_name["F10"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 64, 1, "F11", *group );
- buttons[0x40] = control;
- controls.push_back( control );
- controls_by_name["F11"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 65, 1, "F12", *group );
- buttons[0x41] = control;
- controls.push_back( control );
- controls_by_name["F12"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 66, 1, "F13", *group );
- buttons[0x42] = control;
- controls.push_back( control );
- controls_by_name["F13"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 67, 1, "F14", *group );
- buttons[0x43] = control;
- controls.push_back( control );
- controls_by_name["F14"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 68, 1, "F15", *group );
- buttons[0x44] = control;
- controls.push_back( control );
- controls_by_name["F15"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 69, 1, "F16", *group );
- buttons[0x45] = control;
- controls.push_back( control );
- controls_by_name["F16"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 39, 1, "global_solo", *group );
- buttons[0x27] = control;
- controls.push_back( control );
- controls_by_name["global_solo"] = control;
- group->add( *control );
-
- group = groups["modifiers"];
- control = new Button ( 80, 1, "option", *group );
- buttons[0x50] = control;
- controls.push_back( control );
- controls_by_name["option"] = control;
- group->add( *control );
-
- group = groups["modifiers"];
- control = new Button ( 73, 1, "cmd_alt", *group );
- buttons[0x49] = control;
- controls.push_back( control );
- controls_by_name["cmd_alt"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 74, 1, "on", *group );
- buttons[0x4a] = control;
- controls.push_back( control );
- controls_by_name["on"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 75, 1, "rec_ready", *group );
- buttons[0x4b] = control;
- controls.push_back( control );
- controls_by_name["rec_ready"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 76, 1, "undo", *group );
- buttons[0x4c] = control;
- controls.push_back( control );
- controls_by_name["undo"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 77, 1, "snapshot", *group );
- buttons[0x4d] = control;
- controls.push_back( control );
- controls_by_name["snapshot"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 79, 1, "redo", *group );
- buttons[0x4f] = control;
- controls.push_back( control );
- controls_by_name["redo"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 71, 1, "marker", *group );
- buttons[0x47] = control;
- controls.push_back( control );
- controls_by_name["marker"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 81, 1, "enter", *group );
- buttons[0x51] = control;
- controls.push_back( control );
- controls_by_name["enter"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 82, 1, "cancel", *group );
- buttons[0x52] = control;
- controls.push_back( control );
- controls_by_name["cancel"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 83, 1, "mixer", *group );
- buttons[0x53] = control;
- controls.push_back( control );
- controls_by_name["mixer"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 91, 1, "frm_left", *group );
- buttons[0x5b] = control;
- controls.push_back( control );
- controls_by_name["frm_left"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 92, 1, "frm_right", *group );
- buttons[0x5c] = control;
- controls.push_back( control );
- controls_by_name["frm_right"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 70, 1, "loop", *group );
- buttons[0x46] = control;
- controls.push_back( control );
- controls_by_name["loop"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 72, 1, "punch_in", *group );
- buttons[0x48] = control;
- controls.push_back( control );
- controls_by_name["punch_in"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 78, 1, "punch_out", *group );
- buttons[0x4e] = control;
- controls.push_back( control );
- controls_by_name["punch_out"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 42, 1, "home", *group );
- buttons[0x2a] = control;
- controls.push_back( control );
- controls_by_name["home"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 41, 1, "end", *group );
- buttons[0x29] = control;
- controls.push_back( control );
- controls_by_name["end"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 44, 1, "rewind", *group );
- buttons[0x2c] = control;
- controls.push_back( control );
- controls_by_name["rewind"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 43, 1, "ffwd", *group );
- buttons[0x2b] = control;
- controls.push_back( control );
- controls_by_name["ffwd"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 93, 1, "stop", *group );
- buttons[0x5d] = control;
- controls.push_back( control );
- controls_by_name["stop"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 94, 1, "play", *group );
- buttons[0x5e] = control;
- controls.push_back( control );
- controls_by_name["play"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 31, 1, "record", *group );
- buttons[0x1f] = control;
- controls.push_back( control );
- controls_by_name["record"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 96, 1, "cursor_up", *group );
- buttons[0x60] = control;
- controls.push_back( control );
- controls_by_name["cursor_up"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 97, 1, "cursor_down", *group );
- buttons[0x61] = control;
- controls.push_back( control );
- controls_by_name["cursor_down"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 98, 1, "cursor_left", *group );
- buttons[0x62] = control;
- controls.push_back( control );
- controls_by_name["cursor_left"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 99, 1, "cursor_right", *group );
- buttons[0x63] = control;
- controls.push_back( control );
- controls_by_name["cursor_right"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 100, 1, "zoom", *group );
- buttons[0x64] = control;
- controls.push_back( control );
- controls_by_name["zoom"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 101, 1, "scrub", *group );
- buttons[0x65] = control;
- controls.push_back( control );
- controls_by_name["scrub"] = control;
- group->add( *control );
-
- group = groups["user"];
- control = new Button ( 102, 1, "user_a", *group );
- buttons[0x66] = control;
- controls.push_back( control );
- controls_by_name["user_a"] = control;
- group->add( *control );
-
- group = groups["user"];
- control = new Button ( 103, 1, "user_b", *group );
- buttons[0x67] = control;
- controls.push_back( control );
- controls_by_name["user_b"] = control;
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 104, 1, "fader_touch", *group );
- buttons[0x68] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 105, 2, "fader_touch", *group );
- buttons[0x69] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 106, 3, "fader_touch", *group );
- buttons[0x6a] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 107, 4, "fader_touch", *group );
- buttons[0x6b] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 108, 5, "fader_touch", *group );
- buttons[0x6c] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 109, 6, "fader_touch", *group );
- buttons[0x6d] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 110, 7, "fader_touch", *group );
- buttons[0x6e] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["master"];
- control = new Button ( 111, 1, "fader_touch", *group );
- buttons[0x6f] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["master"];
- control = new Button ( 23, 1, "mute", *group );
- buttons[0x17] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 51, 1, "clicking", *group );
- buttons[0x33] = control;
- controls.push_back( control );
- controls_by_name["clicking"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 113, 1, "smpte", *group );
- leds[0x71] = control;
- controls.push_back( control );
- controls_by_name["smpte"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 114, 1, "beats", *group );
- leds[0x72] = control;
- controls.push_back( control );
- controls_by_name["beats"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 115, 1, "solo", *group );
- leds[0x73] = control;
- controls.push_back( control );
- controls_by_name["solo"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 118, 1, "relay_click", *group );
- leds[0x76] = control;
- controls.push_back( control );
- controls_by_name["relay_click"] = control;
- group->add( *control );
-
-}
-
-void Mackie::BcfSurface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
-{
- if ( bs != press && bs != release )
+ if ( current_bank == 0 )
{
- mbh.update_led( button, none );
- return;
+ // send Ar. to 2-char display on the master
+ port.write( builder.two_char_display( "Ar", ".." ) );
}
-
- LedState ls;
- switch ( button.id() )
+ else
{
+ // write the current first remote_id to the 2-char display
+ port.write( builder.two_char_display( current_bank ) );
+ }
+}
- case 0x28: // io
- switch ( bs ) {
- case press: ls = mbh.io_press( button ); break;
- case release: ls = mbh.io_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5a: // sends
- switch ( bs ) {
- case press: ls = mbh.sends_press( button ); break;
- case release: ls = mbh.sends_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x59: // pan
- switch ( bs ) {
- case press: ls = mbh.pan_press( button ); break;
- case release: ls = mbh.pan_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x57: // plugin
- switch ( bs ) {
- case press: ls = mbh.plugin_press( button ); break;
- case release: ls = mbh.plugin_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x58: // eq
- switch ( bs ) {
- case press: ls = mbh.eq_press( button ); break;
- case release: ls = mbh.eq_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2d: // dyn
- switch ( bs ) {
- case press: ls = mbh.dyn_press( button ); break;
- case release: ls = mbh.dyn_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2e: // left
- switch ( bs ) {
- case press: ls = mbh.left_press( button ); break;
- case release: ls = mbh.left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2f: // right
- switch ( bs ) {
- case press: ls = mbh.right_press( button ); break;
- case release: ls = mbh.right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x30: // channel_left
- switch ( bs ) {
- case press: ls = mbh.channel_left_press( button ); break;
- case release: ls = mbh.channel_left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x31: // channel_right
- switch ( bs ) {
- case press: ls = mbh.channel_right_press( button ); break;
- case release: ls = mbh.channel_right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x32: // flip
- switch ( bs ) {
- case press: ls = mbh.flip_press( button ); break;
- case release: ls = mbh.flip_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x56: // edit
- switch ( bs ) {
- case press: ls = mbh.edit_press( button ); break;
- case release: ls = mbh.edit_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x34: // name_value
- switch ( bs ) {
- case press: ls = mbh.name_value_press( button ); break;
- case release: ls = mbh.name_value_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x35: // smpte_beats
- switch ( bs ) {
- case press: ls = mbh.smpte_beats_press( button ); break;
- case release: ls = mbh.smpte_beats_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x36: // F1
- switch ( bs ) {
- case press: ls = mbh.F1_press( button ); break;
- case release: ls = mbh.F1_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x37: // F2
- switch ( bs ) {
- case press: ls = mbh.F2_press( button ); break;
- case release: ls = mbh.F2_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x38: // F3
- switch ( bs ) {
- case press: ls = mbh.F3_press( button ); break;
- case release: ls = mbh.F3_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x39: // F4
- switch ( bs ) {
- case press: ls = mbh.F4_press( button ); break;
- case release: ls = mbh.F4_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3a: // F5
- switch ( bs ) {
- case press: ls = mbh.F5_press( button ); break;
- case release: ls = mbh.F5_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3b: // F6
- switch ( bs ) {
- case press: ls = mbh.F6_press( button ); break;
- case release: ls = mbh.F6_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3c: // F7
- switch ( bs ) {
- case press: ls = mbh.F7_press( button ); break;
- case release: ls = mbh.F7_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3d: // F8
- switch ( bs ) {
- case press: ls = mbh.F8_press( button ); break;
- case release: ls = mbh.F8_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3e: // F9
- switch ( bs ) {
- case press: ls = mbh.F9_press( button ); break;
- case release: ls = mbh.F9_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3f: // F10
- switch ( bs ) {
- case press: ls = mbh.F10_press( button ); break;
- case release: ls = mbh.F10_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x40: // F11
- switch ( bs ) {
- case press: ls = mbh.F11_press( button ); break;
- case release: ls = mbh.F11_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x41: // F12
- switch ( bs ) {
- case press: ls = mbh.F12_press( button ); break;
- case release: ls = mbh.F12_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x42: // F13
- switch ( bs ) {
- case press: ls = mbh.F13_press( button ); break;
- case release: ls = mbh.F13_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x43: // F14
- switch ( bs ) {
- case press: ls = mbh.F14_press( button ); break;
- case release: ls = mbh.F14_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x44: // F15
- switch ( bs ) {
- case press: ls = mbh.F15_press( button ); break;
- case release: ls = mbh.F15_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x45: // F16
- switch ( bs ) {
- case press: ls = mbh.F16_press( button ); break;
- case release: ls = mbh.F16_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x27: // global_solo
- switch ( bs ) {
- case press: ls = mbh.global_solo_press( button ); break;
- case release: ls = mbh.global_solo_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x50: // option
- switch ( bs ) {
- case press: ls = mbh.option_press( button ); break;
- case release: ls = mbh.option_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x49: // cmd_alt
- switch ( bs ) {
- case press: ls = mbh.cmd_alt_press( button ); break;
- case release: ls = mbh.cmd_alt_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4a: // on
- switch ( bs ) {
- case press: ls = mbh.on_press( button ); break;
- case release: ls = mbh.on_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4b: // rec_ready
- switch ( bs ) {
- case press: ls = mbh.rec_ready_press( button ); break;
- case release: ls = mbh.rec_ready_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4c: // undo
- switch ( bs ) {
- case press: ls = mbh.undo_press( button ); break;
- case release: ls = mbh.undo_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4d: // snapshot
- switch ( bs ) {
- case press: ls = mbh.snapshot_press( button ); break;
- case release: ls = mbh.snapshot_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4f: // redo
- switch ( bs ) {
- case press: ls = mbh.redo_press( button ); break;
- case release: ls = mbh.redo_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x47: // marker
- switch ( bs ) {
- case press: ls = mbh.marker_press( button ); break;
- case release: ls = mbh.marker_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x51: // enter
- switch ( bs ) {
- case press: ls = mbh.enter_press( button ); break;
- case release: ls = mbh.enter_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x52: // cancel
- switch ( bs ) {
- case press: ls = mbh.cancel_press( button ); break;
- case release: ls = mbh.cancel_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x53: // mixer
- switch ( bs ) {
- case press: ls = mbh.mixer_press( button ); break;
- case release: ls = mbh.mixer_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5b: // frm_left
- switch ( bs ) {
- case press: ls = mbh.frm_left_press( button ); break;
- case release: ls = mbh.frm_left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5c: // frm_right
- switch ( bs ) {
- case press: ls = mbh.frm_right_press( button ); break;
- case release: ls = mbh.frm_right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x46: // loop
- switch ( bs ) {
- case press: ls = mbh.loop_press( button ); break;
- case release: ls = mbh.loop_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x48: // punch_in
- switch ( bs ) {
- case press: ls = mbh.punch_in_press( button ); break;
- case release: ls = mbh.punch_in_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4e: // punch_out
- switch ( bs ) {
- case press: ls = mbh.punch_out_press( button ); break;
- case release: ls = mbh.punch_out_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2a: // home
- switch ( bs ) {
- case press: ls = mbh.home_press( button ); break;
- case release: ls = mbh.home_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x29: // end
- switch ( bs ) {
- case press: ls = mbh.end_press( button ); break;
- case release: ls = mbh.end_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2c: // rewind
- switch ( bs ) {
- case press: ls = mbh.rewind_press( button ); break;
- case release: ls = mbh.rewind_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2b: // ffwd
- switch ( bs ) {
- case press: ls = mbh.ffwd_press( button ); break;
- case release: ls = mbh.ffwd_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5d: // stop
- switch ( bs ) {
- case press: ls = mbh.stop_press( button ); break;
- case release: ls = mbh.stop_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5e: // play
- switch ( bs ) {
- case press: ls = mbh.play_press( button ); break;
- case release: ls = mbh.play_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x1f: // record
- switch ( bs ) {
- case press: ls = mbh.record_press( button ); break;
- case release: ls = mbh.record_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x60: // cursor_up
- switch ( bs ) {
- case press: ls = mbh.cursor_up_press( button ); break;
- case release: ls = mbh.cursor_up_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x61: // cursor_down
- switch ( bs ) {
- case press: ls = mbh.cursor_down_press( button ); break;
- case release: ls = mbh.cursor_down_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x62: // cursor_left
- switch ( bs ) {
- case press: ls = mbh.cursor_left_press( button ); break;
- case release: ls = mbh.cursor_left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x63: // cursor_right
- switch ( bs ) {
- case press: ls = mbh.cursor_right_press( button ); break;
- case release: ls = mbh.cursor_right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x64: // zoom
- switch ( bs ) {
- case press: ls = mbh.zoom_press( button ); break;
- case release: ls = mbh.zoom_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x65: // scrub
- switch ( bs ) {
- case press: ls = mbh.scrub_press( button ); break;
- case release: ls = mbh.scrub_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x66: // user_a
- switch ( bs ) {
- case press: ls = mbh.user_a_press( button ); break;
- case release: ls = mbh.user_a_release( button ); break;
- case neither: break;
- }
- break;
+void BcfSurface::zero_all( SurfacePort & port, MackieMidiBuilder & builder )
+{
+ // clear 2-char display
+ port.write( builder.two_char_display( "LC" ) );
- case 0x67: // user_b
- switch ( bs ) {
- case press: ls = mbh.user_b_press( button ); break;
- case release: ls = mbh.user_b_release( button ); break;
- case neither: break;
- }
- break;
+ // and the led ring for the master strip
+ blank_jog_ring( port, builder );
+}
- case 0x33: // clicking
- switch ( bs ) {
- case press: ls = mbh.clicking_press( button ); break;
- case release: ls = mbh.clicking_release( button ); break;
- case neither: break;
- }
- break;
+void BcfSurface::blank_jog_ring( SurfacePort & port, MackieMidiBuilder & builder )
+{
+ Control & control = *controls_by_name["jog"];
+ port.write( builder.build_led_ring( dynamic_cast<Pot &>( control ), off ) );
+}
- }
- mbh.update_led( button, ls );
+float BcfSurface::scaled_delta( const ControlState & state, float current_speed )
+{
+ return state.sign * ( std::pow( float(state.ticks + 1), 2 ) + current_speed ) / 100.0;
}
+
diff --git a/libs/surfaces/mackie/bcf_surface.h b/libs/surfaces/mackie/bcf_surface.h
index a5fd3bf5a3..95bb27db01 100644
--- a/libs/surfaces/mackie/bcf_surface.h
+++ b/libs/surfaces/mackie/bcf_surface.h
@@ -1,7 +1,7 @@
#ifndef mackie_surface_bcf_h
#define mackie_surface_bcf_h
/*
- Generated by scripts/generate-surface.rb
+ Initially generated by scripts/generate-surface.rb
*/
#include "surface.h"
@@ -20,6 +20,15 @@ public:
virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
virtual void init_controls();
+
+ virtual void display_bank_start( SurfacePort & port, MackieMidiBuilder & builder, uint32_t current_bank );
+ virtual void zero_all( SurfacePort & port, MackieMidiBuilder & builder );
+ virtual void blank_jog_ring( SurfacePort & port, MackieMidiBuilder & builder );
+ virtual bool has_timecode_display() const { return false; }
+
+ virtual float scrub_scaling_factor() { return 50.0; }
+ virtual float scaled_delta( const ControlState & state, float current_speed );
+
};
}
diff --git a/libs/surfaces/mackie/bcf_surface_generated.cc b/libs/surfaces/mackie/bcf_surface_generated.cc
new file mode 100644
index 0000000000..f1d8d7ab7b
--- /dev/null
+++ b/libs/surfaces/mackie/bcf_surface_generated.cc
@@ -0,0 +1,1461 @@
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "bcf_surface.h"
+
+#include "controls.h"
+#include "mackie_button_handler.h"
+
+using namespace Mackie;
+
+void Mackie::BcfSurface::init_controls()
+{
+ // intialise groups and strips
+ Group * group = 0;
+
+ // make sure there are enough strips
+ strips.resize( 7 );
+
+ group = new Group ( "user" );
+ groups["user"] = group;
+
+ group = new Group ( "assignment" );
+ groups["assignment"] = group;
+
+ group = new Group ( "none" );
+ groups["none"] = group;
+
+ group = new MasterStrip ( "master", 0 );
+ groups["master"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_1", 0 );
+ groups["strip_1"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "cursor" );
+ groups["cursor"] = group;
+
+ group = new Strip ( "strip_2", 1 );
+ groups["strip_2"] = group;
+ strips[1] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "automation" );
+ groups["automation"] = group;
+
+ group = new Group ( "functions" );
+ groups["functions"] = group;
+
+ group = new Strip ( "strip_3", 2 );
+ groups["strip_3"] = group;
+ strips[2] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "display" );
+ groups["display"] = group;
+
+ group = new Strip ( "strip_4", 3 );
+ groups["strip_4"] = group;
+ strips[3] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_5", 4 );
+ groups["strip_5"] = group;
+ strips[4] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_6", 5 );
+ groups["strip_6"] = group;
+ strips[5] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "transport" );
+ groups["transport"] = group;
+
+ group = new Strip ( "strip_7", 6 );
+ groups["strip_7"] = group;
+ strips[6] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "modifiers" );
+ groups["modifiers"] = group;
+
+ group = new Group ( "bank" );
+ groups["bank"] = group;
+
+
+ // initialise controls
+ Fader * fader = 0;
+ Pot * pot = 0;
+ Button * button = 0;
+ Led * led = 0;
+
+ group = groups["strip_1"];
+ fader = new Fader ( 0, 1, "gain", *group );
+ faders[0x00] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_2"];
+ fader = new Fader ( 1, 2, "gain", *group );
+ faders[0x01] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_3"];
+ fader = new Fader ( 2, 3, "gain", *group );
+ faders[0x02] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_4"];
+ fader = new Fader ( 3, 4, "gain", *group );
+ faders[0x03] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_5"];
+ fader = new Fader ( 4, 5, "gain", *group );
+ faders[0x04] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_6"];
+ fader = new Fader ( 5, 6, "gain", *group );
+ faders[0x05] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_7"];
+ fader = new Fader ( 6, 7, "gain", *group );
+ faders[0x06] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["master"];
+ fader = new Fader ( 7, 1, "gain", *group );
+ faders[0x07] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_1"];
+ pot = new Pot ( 16, 1, "vpot", *group );
+ pots[0x10] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_2"];
+ pot = new Pot ( 17, 2, "vpot", *group );
+ pots[0x11] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_3"];
+ pot = new Pot ( 18, 3, "vpot", *group );
+ pots[0x12] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_4"];
+ pot = new Pot ( 19, 4, "vpot", *group );
+ pots[0x13] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_5"];
+ pot = new Pot ( 20, 5, "vpot", *group );
+ pots[0x14] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_6"];
+ pot = new Pot ( 21, 6, "vpot", *group );
+ pots[0x15] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_7"];
+ pot = new Pot ( 22, 7, "vpot", *group );
+ pots[0x16] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["none"];
+ pot = new Jog ( 23, 1, "jog", *group );
+ pots[0x17] = pot;
+ controls.push_back( pot );
+ controls_by_name["jog"] = pot;
+ group->add( *pot );
+
+ group = groups["none"];
+ pot = new Pot ( 46, 1, "external", *group );
+ pots[0x2e] = pot;
+ controls.push_back( pot );
+ controls_by_name["external"] = pot;
+ group->add( *pot );
+
+ group = groups["strip_1"];
+ button = new Button ( 24, 1, "recenable", *group );
+ buttons[0x18] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 25, 2, "recenable", *group );
+ buttons[0x19] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 26, 3, "recenable", *group );
+ buttons[0x1a] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 27, 4, "recenable", *group );
+ buttons[0x1b] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 28, 5, "recenable", *group );
+ buttons[0x1c] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 29, 6, "recenable", *group );
+ buttons[0x1d] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 30, 7, "recenable", *group );
+ buttons[0x1e] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 32, 1, "solo", *group );
+ buttons[0x20] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 33, 2, "solo", *group );
+ buttons[0x21] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 34, 3, "solo", *group );
+ buttons[0x22] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 35, 4, "solo", *group );
+ buttons[0x23] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 36, 5, "solo", *group );
+ buttons[0x24] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 37, 6, "solo", *group );
+ buttons[0x25] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 38, 7, "solo", *group );
+ buttons[0x26] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 16, 1, "mute", *group );
+ buttons[0x10] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 17, 2, "mute", *group );
+ buttons[0x11] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 18, 3, "mute", *group );
+ buttons[0x12] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 19, 4, "mute", *group );
+ buttons[0x13] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 20, 5, "mute", *group );
+ buttons[0x14] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 21, 6, "mute", *group );
+ buttons[0x15] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 22, 7, "mute", *group );
+ buttons[0x16] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 0, 1, "select", *group );
+ buttons[0x00] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 1, 2, "select", *group );
+ buttons[0x01] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 2, 3, "select", *group );
+ buttons[0x02] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 3, 4, "select", *group );
+ buttons[0x03] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 4, 5, "select", *group );
+ buttons[0x04] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 5, 6, "select", *group );
+ buttons[0x05] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 6, 7, "select", *group );
+ buttons[0x06] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 8, 1, "vselect", *group );
+ buttons[0x08] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 9, 2, "vselect", *group );
+ buttons[0x09] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 10, 3, "vselect", *group );
+ buttons[0x0a] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 11, 4, "vselect", *group );
+ buttons[0x0b] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 12, 5, "vselect", *group );
+ buttons[0x0c] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 13, 6, "vselect", *group );
+ buttons[0x0d] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 14, 7, "vselect", *group );
+ buttons[0x0e] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 40, 1, "io", *group );
+ buttons[0x28] = button;
+ controls.push_back( button );
+ controls_by_name["io"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 90, 1, "sends", *group );
+ buttons[0x5a] = button;
+ controls.push_back( button );
+ controls_by_name["sends"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 89, 1, "pan", *group );
+ buttons[0x59] = button;
+ controls.push_back( button );
+ controls_by_name["pan"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 87, 1, "plugin", *group );
+ buttons[0x57] = button;
+ controls.push_back( button );
+ controls_by_name["plugin"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 88, 1, "drop", *group );
+ buttons[0x58] = button;
+ controls.push_back( button );
+ controls_by_name["drop"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 45, 1, "zoom", *group );
+ buttons[0x2d] = button;
+ controls.push_back( button );
+ controls_by_name["zoom"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 46, 1, "left", *group );
+ buttons[0x2e] = button;
+ controls.push_back( button );
+ controls_by_name["left"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 47, 1, "right", *group );
+ buttons[0x2f] = button;
+ controls.push_back( button );
+ controls_by_name["right"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 48, 1, "channel_left", *group );
+ buttons[0x30] = button;
+ controls.push_back( button );
+ controls_by_name["channel_left"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 49, 1, "channel_right", *group );
+ buttons[0x31] = button;
+ controls.push_back( button );
+ controls_by_name["channel_right"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 50, 1, "scrub", *group );
+ buttons[0x32] = button;
+ controls.push_back( button );
+ controls_by_name["scrub"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 86, 1, "edit", *group );
+ buttons[0x56] = button;
+ controls.push_back( button );
+ controls_by_name["edit"] = button;
+ group->add( *button );
+
+ group = groups["display"];
+ button = new Button ( 52, 1, "name_value", *group );
+ buttons[0x34] = button;
+ controls.push_back( button );
+ controls_by_name["name_value"] = button;
+ group->add( *button );
+
+ group = groups["display"];
+ button = new Button ( 53, 1, "smpte_beats", *group );
+ buttons[0x35] = button;
+ controls.push_back( button );
+ controls_by_name["smpte_beats"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 54, 1, "F1", *group );
+ buttons[0x36] = button;
+ controls.push_back( button );
+ controls_by_name["F1"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 55, 1, "F2", *group );
+ buttons[0x37] = button;
+ controls.push_back( button );
+ controls_by_name["F2"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 56, 1, "F3", *group );
+ buttons[0x38] = button;
+ controls.push_back( button );
+ controls_by_name["F3"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 57, 1, "F4", *group );
+ buttons[0x39] = button;
+ controls.push_back( button );
+ controls_by_name["F4"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 58, 1, "F5", *group );
+ buttons[0x3a] = button;
+ controls.push_back( button );
+ controls_by_name["F5"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 59, 1, "F6", *group );
+ buttons[0x3b] = button;
+ controls.push_back( button );
+ controls_by_name["F6"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 60, 1, "F7", *group );
+ buttons[0x3c] = button;
+ controls.push_back( button );
+ controls_by_name["F7"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 61, 1, "F8", *group );
+ buttons[0x3d] = button;
+ controls.push_back( button );
+ controls_by_name["F8"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 62, 1, "F9", *group );
+ buttons[0x3e] = button;
+ controls.push_back( button );
+ controls_by_name["F9"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 63, 1, "F10", *group );
+ buttons[0x3f] = button;
+ controls.push_back( button );
+ controls_by_name["F10"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 64, 1, "F11", *group );
+ buttons[0x40] = button;
+ controls.push_back( button );
+ controls_by_name["F11"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 65, 1, "F12", *group );
+ buttons[0x41] = button;
+ controls.push_back( button );
+ controls_by_name["F12"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 66, 1, "F13", *group );
+ buttons[0x42] = button;
+ controls.push_back( button );
+ controls_by_name["F13"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 67, 1, "F14", *group );
+ buttons[0x43] = button;
+ controls.push_back( button );
+ controls_by_name["F14"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 68, 1, "F15", *group );
+ buttons[0x44] = button;
+ controls.push_back( button );
+ controls_by_name["F15"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 69, 1, "F16", *group );
+ buttons[0x45] = button;
+ controls.push_back( button );
+ controls_by_name["F16"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 39, 1, "global_solo", *group );
+ buttons[0x27] = button;
+ controls.push_back( button );
+ controls_by_name["global_solo"] = button;
+ group->add( *button );
+
+ group = groups["modifiers"];
+ button = new Button ( 80, 1, "option", *group );
+ buttons[0x50] = button;
+ controls.push_back( button );
+ controls_by_name["option"] = button;
+ group->add( *button );
+
+ group = groups["modifiers"];
+ button = new Button ( 73, 1, "cmd_alt", *group );
+ buttons[0x49] = button;
+ controls.push_back( button );
+ controls_by_name["cmd_alt"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 74, 1, "on", *group );
+ buttons[0x4a] = button;
+ controls.push_back( button );
+ controls_by_name["on"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 75, 1, "rec_ready", *group );
+ buttons[0x4b] = button;
+ controls.push_back( button );
+ controls_by_name["rec_ready"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 76, 1, "undo", *group );
+ buttons[0x4c] = button;
+ controls.push_back( button );
+ controls_by_name["undo"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 95, 1, "snapshot", *group );
+ buttons[0x5f] = button;
+ controls.push_back( button );
+ controls_by_name["snapshot"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 79, 1, "redo", *group );
+ buttons[0x4f] = button;
+ controls.push_back( button );
+ controls_by_name["redo"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 71, 1, "marker", *group );
+ buttons[0x47] = button;
+ controls.push_back( button );
+ controls_by_name["marker"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 81, 1, "enter", *group );
+ buttons[0x51] = button;
+ controls.push_back( button );
+ controls_by_name["enter"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 82, 1, "cancel", *group );
+ buttons[0x52] = button;
+ controls.push_back( button );
+ controls_by_name["cancel"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 83, 1, "mixer", *group );
+ buttons[0x53] = button;
+ controls.push_back( button );
+ controls_by_name["mixer"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 77, 1, "save", *group );
+ buttons[0x4d] = button;
+ controls.push_back( button );
+ controls_by_name["save"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 91, 1, "frm_left", *group );
+ buttons[0x5b] = button;
+ controls.push_back( button );
+ controls_by_name["frm_left"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 92, 1, "frm_right", *group );
+ buttons[0x5c] = button;
+ controls.push_back( button );
+ controls_by_name["frm_right"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 70, 1, "loop", *group );
+ buttons[0x46] = button;
+ controls.push_back( button );
+ controls_by_name["loop"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 72, 1, "punch_in", *group );
+ buttons[0x48] = button;
+ controls.push_back( button );
+ controls_by_name["punch_in"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 78, 1, "punch_out", *group );
+ buttons[0x4e] = button;
+ controls.push_back( button );
+ controls_by_name["punch_out"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 42, 1, "home", *group );
+ buttons[0x2a] = button;
+ controls.push_back( button );
+ controls_by_name["home"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 41, 1, "end", *group );
+ buttons[0x29] = button;
+ controls.push_back( button );
+ controls_by_name["end"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 44, 1, "rewind", *group );
+ buttons[0x2c] = button;
+ controls.push_back( button );
+ controls_by_name["rewind"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 43, 1, "ffwd", *group );
+ buttons[0x2b] = button;
+ controls.push_back( button );
+ controls_by_name["ffwd"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 93, 1, "stop", *group );
+ buttons[0x5d] = button;
+ controls.push_back( button );
+ controls_by_name["stop"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 94, 1, "play", *group );
+ buttons[0x5e] = button;
+ controls.push_back( button );
+ controls_by_name["play"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 31, 1, "record", *group );
+ buttons[0x1f] = button;
+ controls.push_back( button );
+ controls_by_name["record"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 96, 1, "cursor_up", *group );
+ buttons[0x60] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_up"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 97, 1, "cursor_down", *group );
+ buttons[0x61] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_down"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 98, 1, "cursor_left", *group );
+ buttons[0x62] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_left"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 99, 1, "cursor_right", *group );
+ buttons[0x63] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_right"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 100, 1, "dyn", *group );
+ buttons[0x64] = button;
+ controls.push_back( button );
+ controls_by_name["dyn"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 101, 1, "flip", *group );
+ buttons[0x65] = button;
+ controls.push_back( button );
+ controls_by_name["flip"] = button;
+ group->add( *button );
+
+ group = groups["user"];
+ button = new Button ( 102, 1, "user_a", *group );
+ buttons[0x66] = button;
+ controls.push_back( button );
+ controls_by_name["user_a"] = button;
+ group->add( *button );
+
+ group = groups["user"];
+ button = new Button ( 103, 1, "user_b", *group );
+ buttons[0x67] = button;
+ controls.push_back( button );
+ controls_by_name["user_b"] = button;
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 104, 1, "fader_touch", *group );
+ buttons[0x68] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 105, 2, "fader_touch", *group );
+ buttons[0x69] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 106, 3, "fader_touch", *group );
+ buttons[0x6a] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 107, 4, "fader_touch", *group );
+ buttons[0x6b] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 108, 5, "fader_touch", *group );
+ buttons[0x6c] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 109, 6, "fader_touch", *group );
+ buttons[0x6d] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 110, 7, "fader_touch", *group );
+ buttons[0x6e] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["master"];
+ button = new Button ( 111, 1, "fader_touch", *group );
+ buttons[0x6f] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["master"];
+ button = new Button ( 23, 1, "mute", *group );
+ buttons[0x17] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 51, 1, "clicking", *group );
+ buttons[0x33] = button;
+ controls.push_back( button );
+ controls_by_name["clicking"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ led = new Led ( 113, 1, "smpte", *group );
+ leds[0x71] = led;
+ controls.push_back( led );
+ controls_by_name["smpte"] = led;
+ group->add( *led );
+
+ group = groups["none"];
+ led = new Led ( 114, 1, "beats", *group );
+ leds[0x72] = led;
+ controls.push_back( led );
+ controls_by_name["beats"] = led;
+ group->add( *led );
+
+ group = groups["none"];
+ led = new Led ( 115, 1, "solo", *group );
+ leds[0x73] = led;
+ controls.push_back( led );
+ controls_by_name["solo"] = led;
+ group->add( *led );
+
+ group = groups["none"];
+ led = new Led ( 118, 1, "relay_click", *group );
+ leds[0x76] = led;
+ controls.push_back( led );
+ controls_by_name["relay_click"] = led;
+ group->add( *led );
+
+}
+
+void Mackie::BcfSurface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
+{
+ if ( bs != press && bs != release )
+ {
+ mbh.update_led( button, none );
+ return;
+ }
+
+ LedState ls;
+ switch ( button.id() )
+ {
+
+ case 0x9028: // io
+ switch ( bs ) {
+ case press: ls = mbh.io_press( button ); break;
+ case release: ls = mbh.io_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905a: // sends
+ switch ( bs ) {
+ case press: ls = mbh.sends_press( button ); break;
+ case release: ls = mbh.sends_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9059: // pan
+ switch ( bs ) {
+ case press: ls = mbh.pan_press( button ); break;
+ case release: ls = mbh.pan_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9057: // plugin
+ switch ( bs ) {
+ case press: ls = mbh.plugin_press( button ); break;
+ case release: ls = mbh.plugin_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9058: // drop
+ switch ( bs ) {
+ case press: ls = mbh.drop_press( button ); break;
+ case release: ls = mbh.drop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902d: // zoom
+ switch ( bs ) {
+ case press: ls = mbh.zoom_press( button ); break;
+ case release: ls = mbh.zoom_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902e: // left
+ switch ( bs ) {
+ case press: ls = mbh.left_press( button ); break;
+ case release: ls = mbh.left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902f: // right
+ switch ( bs ) {
+ case press: ls = mbh.right_press( button ); break;
+ case release: ls = mbh.right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9030: // channel_left
+ switch ( bs ) {
+ case press: ls = mbh.channel_left_press( button ); break;
+ case release: ls = mbh.channel_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9031: // channel_right
+ switch ( bs ) {
+ case press: ls = mbh.channel_right_press( button ); break;
+ case release: ls = mbh.channel_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9032: // scrub
+ switch ( bs ) {
+ case press: ls = mbh.scrub_press( button ); break;
+ case release: ls = mbh.scrub_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9056: // edit
+ switch ( bs ) {
+ case press: ls = mbh.edit_press( button ); break;
+ case release: ls = mbh.edit_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9034: // name_value
+ switch ( bs ) {
+ case press: ls = mbh.name_value_press( button ); break;
+ case release: ls = mbh.name_value_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9035: // smpte_beats
+ switch ( bs ) {
+ case press: ls = mbh.smpte_beats_press( button ); break;
+ case release: ls = mbh.smpte_beats_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9036: // F1
+ switch ( bs ) {
+ case press: ls = mbh.F1_press( button ); break;
+ case release: ls = mbh.F1_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9037: // F2
+ switch ( bs ) {
+ case press: ls = mbh.F2_press( button ); break;
+ case release: ls = mbh.F2_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9038: // F3
+ switch ( bs ) {
+ case press: ls = mbh.F3_press( button ); break;
+ case release: ls = mbh.F3_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9039: // F4
+ switch ( bs ) {
+ case press: ls = mbh.F4_press( button ); break;
+ case release: ls = mbh.F4_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903a: // F5
+ switch ( bs ) {
+ case press: ls = mbh.F5_press( button ); break;
+ case release: ls = mbh.F5_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903b: // F6
+ switch ( bs ) {
+ case press: ls = mbh.F6_press( button ); break;
+ case release: ls = mbh.F6_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903c: // F7
+ switch ( bs ) {
+ case press: ls = mbh.F7_press( button ); break;
+ case release: ls = mbh.F7_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903d: // F8
+ switch ( bs ) {
+ case press: ls = mbh.F8_press( button ); break;
+ case release: ls = mbh.F8_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903e: // F9
+ switch ( bs ) {
+ case press: ls = mbh.F9_press( button ); break;
+ case release: ls = mbh.F9_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903f: // F10
+ switch ( bs ) {
+ case press: ls = mbh.F10_press( button ); break;
+ case release: ls = mbh.F10_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9040: // F11
+ switch ( bs ) {
+ case press: ls = mbh.F11_press( button ); break;
+ case release: ls = mbh.F11_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9041: // F12
+ switch ( bs ) {
+ case press: ls = mbh.F12_press( button ); break;
+ case release: ls = mbh.F12_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9042: // F13
+ switch ( bs ) {
+ case press: ls = mbh.F13_press( button ); break;
+ case release: ls = mbh.F13_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9043: // F14
+ switch ( bs ) {
+ case press: ls = mbh.F14_press( button ); break;
+ case release: ls = mbh.F14_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9044: // F15
+ switch ( bs ) {
+ case press: ls = mbh.F15_press( button ); break;
+ case release: ls = mbh.F15_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9045: // F16
+ switch ( bs ) {
+ case press: ls = mbh.F16_press( button ); break;
+ case release: ls = mbh.F16_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9027: // global_solo
+ switch ( bs ) {
+ case press: ls = mbh.global_solo_press( button ); break;
+ case release: ls = mbh.global_solo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9050: // option
+ switch ( bs ) {
+ case press: ls = mbh.option_press( button ); break;
+ case release: ls = mbh.option_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9049: // cmd_alt
+ switch ( bs ) {
+ case press: ls = mbh.cmd_alt_press( button ); break;
+ case release: ls = mbh.cmd_alt_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904a: // on
+ switch ( bs ) {
+ case press: ls = mbh.on_press( button ); break;
+ case release: ls = mbh.on_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904b: // rec_ready
+ switch ( bs ) {
+ case press: ls = mbh.rec_ready_press( button ); break;
+ case release: ls = mbh.rec_ready_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904c: // undo
+ switch ( bs ) {
+ case press: ls = mbh.undo_press( button ); break;
+ case release: ls = mbh.undo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905f: // snapshot
+ switch ( bs ) {
+ case press: ls = mbh.snapshot_press( button ); break;
+ case release: ls = mbh.snapshot_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904f: // redo
+ switch ( bs ) {
+ case press: ls = mbh.redo_press( button ); break;
+ case release: ls = mbh.redo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9047: // marker
+ switch ( bs ) {
+ case press: ls = mbh.marker_press( button ); break;
+ case release: ls = mbh.marker_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9051: // enter
+ switch ( bs ) {
+ case press: ls = mbh.enter_press( button ); break;
+ case release: ls = mbh.enter_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9052: // cancel
+ switch ( bs ) {
+ case press: ls = mbh.cancel_press( button ); break;
+ case release: ls = mbh.cancel_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9053: // mixer
+ switch ( bs ) {
+ case press: ls = mbh.mixer_press( button ); break;
+ case release: ls = mbh.mixer_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904d: // save
+ switch ( bs ) {
+ case press: ls = mbh.save_press( button ); break;
+ case release: ls = mbh.save_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905b: // frm_left
+ switch ( bs ) {
+ case press: ls = mbh.frm_left_press( button ); break;
+ case release: ls = mbh.frm_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905c: // frm_right
+ switch ( bs ) {
+ case press: ls = mbh.frm_right_press( button ); break;
+ case release: ls = mbh.frm_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9046: // loop
+ switch ( bs ) {
+ case press: ls = mbh.loop_press( button ); break;
+ case release: ls = mbh.loop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9048: // punch_in
+ switch ( bs ) {
+ case press: ls = mbh.punch_in_press( button ); break;
+ case release: ls = mbh.punch_in_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904e: // punch_out
+ switch ( bs ) {
+ case press: ls = mbh.punch_out_press( button ); break;
+ case release: ls = mbh.punch_out_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902a: // home
+ switch ( bs ) {
+ case press: ls = mbh.home_press( button ); break;
+ case release: ls = mbh.home_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9029: // end
+ switch ( bs ) {
+ case press: ls = mbh.end_press( button ); break;
+ case release: ls = mbh.end_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902c: // rewind
+ switch ( bs ) {
+ case press: ls = mbh.rewind_press( button ); break;
+ case release: ls = mbh.rewind_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902b: // ffwd
+ switch ( bs ) {
+ case press: ls = mbh.ffwd_press( button ); break;
+ case release: ls = mbh.ffwd_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905d: // stop
+ switch ( bs ) {
+ case press: ls = mbh.stop_press( button ); break;
+ case release: ls = mbh.stop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905e: // play
+ switch ( bs ) {
+ case press: ls = mbh.play_press( button ); break;
+ case release: ls = mbh.play_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x901f: // record
+ switch ( bs ) {
+ case press: ls = mbh.record_press( button ); break;
+ case release: ls = mbh.record_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9060: // cursor_up
+ switch ( bs ) {
+ case press: ls = mbh.cursor_up_press( button ); break;
+ case release: ls = mbh.cursor_up_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9061: // cursor_down
+ switch ( bs ) {
+ case press: ls = mbh.cursor_down_press( button ); break;
+ case release: ls = mbh.cursor_down_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9062: // cursor_left
+ switch ( bs ) {
+ case press: ls = mbh.cursor_left_press( button ); break;
+ case release: ls = mbh.cursor_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9063: // cursor_right
+ switch ( bs ) {
+ case press: ls = mbh.cursor_right_press( button ); break;
+ case release: ls = mbh.cursor_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9064: // dyn
+ switch ( bs ) {
+ case press: ls = mbh.dyn_press( button ); break;
+ case release: ls = mbh.dyn_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9065: // flip
+ switch ( bs ) {
+ case press: ls = mbh.flip_press( button ); break;
+ case release: ls = mbh.flip_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9066: // user_a
+ switch ( bs ) {
+ case press: ls = mbh.user_a_press( button ); break;
+ case release: ls = mbh.user_a_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9067: // user_b
+ switch ( bs ) {
+ case press: ls = mbh.user_b_press( button ); break;
+ case release: ls = mbh.user_b_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9033: // clicking
+ switch ( bs ) {
+ case press: ls = mbh.clicking_press( button ); break;
+ case release: ls = mbh.clicking_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ }
+ mbh.update_led( button, ls );
+}
diff --git a/libs/surfaces/mackie/controls.cc b/libs/surfaces/mackie/controls.cc
index e9808119b2..d73530f95b 100644
--- a/libs/surfaces/mackie/controls.cc
+++ b/libs/surfaces/mackie/controls.cc
@@ -46,6 +46,76 @@ Strip::Strip( const std::string & name, int index )
}
/**
+ TODO could optimise this to use enum, but it's only
+ called during the protocol class instantiation.
+
+ generated using
+
+ irb -r controls.rb
+ sf=Surface.new
+ sf.parse
+ controls = sf.groups.find{|x| x[0] =~ /strip/}.each{|x| puts x[1]}
+ controls[1].each {|x| puts "\telse if ( control.name() == \"#{x.name}\" )\n\t{\n\t\t_#{x.name} = reinterpret_cast<#{x.class.name}*>(&control);\n\t}\n"}
+*/
+void Strip::add( Control & control )
+{
+ Group::add( control );
+ if ( control.name() == "gain" )
+ {
+ _gain = reinterpret_cast<Fader*>(&control);
+ }
+ else if ( control.name() == "vpot" )
+ {
+ _vpot = reinterpret_cast<Pot*>(&control);
+ }
+ else if ( control.name() == "recenable" )
+ {
+ _recenable = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "solo" )
+ {
+ _solo = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "mute" )
+ {
+ _mute = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "select" )
+ {
+ _select = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "vselect" )
+ {
+ _vselect = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.name() == "fader_touch" )
+ {
+ _fader_touch = reinterpret_cast<Button*>(&control);
+ }
+ else if ( control.type() == Control::type_led || control.type() == Control::type_led_ring )
+ {
+ // do nothing
+ cout << "Strip::add not adding " << control << endl;
+ }
+ else
+ {
+ ostringstream os;
+ os << "Strip::add: unknown control type " << control;
+ throw MackieControlException( os.str() );
+ }
+}
+
+Control::Control( int id, int ordinal, std::string name, Group & group )
+: _id( id )
+, _ordinal( ordinal )
+, _name( name )
+, _group( group )
+, _in_use( false )
+, _in_use_timeout( 250 )
+{
+}
+
+/**
generated with
controls[1].each do |x|
@@ -107,3 +177,58 @@ Button & Strip::fader_touch()
throw MackieControlException( "fader_touch is null" );
return *_fader_touch;
}
+
+bool Control::in_use() const
+{
+ return _in_use;
+}
+
+Control & Control::in_use( bool rhs )
+{
+ _in_use = rhs;
+ return *this;
+}
+
+ostream & Mackie::operator << ( ostream & os, const Mackie::Control & control )
+{
+ os << typeid( control ).name();
+ os << " { ";
+ os << "name: " << control.name();
+ os << ", ";
+ os << "id: " << "0x" << setw(4) << setfill('0') << hex << control.id() << setfill(' ');
+ os << ", ";
+ os << "type: " << "0x" << setw(2) << setfill('0') << hex << control.type() << setfill(' ');
+ os << ", ";
+ os << "raw_id: " << "0x" << setw(2) << setfill('0') << hex << control.raw_id() << setfill(' ');
+ os << ", ";
+ os << "ordinal: " << dec << control.ordinal();
+ os << ", ";
+ os << "group: " << control.group().name();
+ os << " }";
+
+ return os;
+}
+
+std::ostream & Mackie::operator << ( std::ostream & os, const Strip & strip )
+{
+ os << typeid( strip ).name();
+ os << " { ";
+ os << "has_solo: " << boolalpha << strip.has_solo();
+ os << ", ";
+ os << "has_recenable: " << boolalpha << strip.has_recenable();
+ os << ", ";
+ os << "has_mute: " << boolalpha << strip.has_mute();
+ os << ", ";
+ os << "has_select: " << boolalpha << strip.has_select();
+ os << ", ";
+ os << "has_vselect: " << boolalpha << strip.has_vselect();
+ os << ", ";
+ os << "has_fader_touch: " << boolalpha << strip.has_fader_touch();
+ os << ", ";
+ os << "has_vpot: " << boolalpha << strip.has_vpot();
+ os << ", ";
+ os << "has_gain: " << boolalpha << strip.has_gain();
+ os << " }";
+
+ return os;
+}
diff --git a/libs/surfaces/mackie/controls.h b/libs/surfaces/mackie/controls.h
index 1092c40453..84283f3016 100644
--- a/libs/surfaces/mackie/controls.h
+++ b/libs/surfaces/mackie/controls.h
@@ -18,6 +18,8 @@
#ifndef mackie_controls_h
#define mackie_controls_h
+#include <sigc++/sigc++.h>
+
#include <map>
#include <vector>
#include <string>
@@ -83,6 +85,9 @@ class Fader;
class Strip : public Group
{
public:
+ /**
+ \param is the index of the strip. 0-based.
+ */
Strip( const std::string & name, int index );
virtual bool is_strip() const
@@ -92,10 +97,11 @@ public:
virtual void add( Control & control );
- /// This is the index of the strip
+ /// This is the index of the strip. zero-based.
int index() const { return _index; }
/// This is for Surface only
+ /// index is zero-based
void index( int rhs ) { _index = rhs; }
Button & solo();
@@ -107,14 +113,14 @@ public:
Pot & vpot();
Fader & gain();
- bool has_solo() { return _solo != 0; }
- bool has_recenable() { return _recenable != 0; }
- bool has_mute() { return _mute != 0; }
- bool has_select() { return _select != 0; }
- bool has_vselect() { return _vselect != 0; }
- bool has_fader_touch() { return _fader_touch != 0; }
- bool has_vpot() { return _vpot != 0; }
- bool has_gain() { return _gain != 0; }
+ bool has_solo() const { return _solo != 0; }
+ bool has_recenable() const { return _recenable != 0; }
+ bool has_mute() const { return _mute != 0; }
+ bool has_select() const { return _select != 0; }
+ bool has_vselect() const { return _vselect != 0; }
+ bool has_fader_touch() const { return _fader_touch != 0; }
+ bool has_vpot() const { return _vpot != 0; }
+ bool has_gain() const { return _gain != 0; }
private:
Button * _solo;
@@ -128,6 +134,8 @@ private:
int _index;
};
+std::ostream & operator << ( std::ostream &, const Strip & );
+
class MasterStrip : public Strip
{
public:
@@ -151,13 +159,9 @@ class Led;
class Control
{
public:
- enum type_t { type_fader, type_button, type_pot, type_led, type_led_ring };
-
- Control( int id, int ordinal, std::string name, Group & group )
- : _id( id ), _ordinal( ordinal ), _name( name ), _group( group )
- {
- }
+ enum type_t { type_led, type_led_ring, type_fader = 0xe0, type_button = 0x90, type_pot = 0xb0 };
+ Control( int id, int ordinal, std::string name, Group & group );
virtual ~Control() {}
virtual const Led & led() const
@@ -165,17 +169,20 @@ public:
throw MackieControlException( "no led available" );
}
- /// The midi id of the control
+ /// type() << 8 + midi id of the control. This
+ /// provides a unique id for any control on the surface.
int id() const
{
- return _id;
+ return ( type() << 8 ) + _id;
}
+ /// the value of the second bytes of the message. It's
+ /// the id of the control, but only guaranteed to be
+ /// unique within the control type.
+ int raw_id() const { return _id; }
+
/// The 1-based number of the control
- int ordinal() const
- {
- return _ordinal;
- }
+ int ordinal() const { return _ordinal; }
const std::string & name() const
{
@@ -204,11 +211,32 @@ public:
virtual type_t type() const = 0;
+ /// Return true if this control is the one and only Jog Wheel
+ virtual bool is_jog() const { return false; }
+
+ /**
+ Return true if the controlis in use, or false otherwise. For buttons
+ this returns true if the button is currently being held down. For
+ faders, the touch button has not been released. For pots, this returns
+ true from the first move event until a timeout after the last move event.
+ */
+ virtual bool in_use() const;
+ virtual Control & in_use( bool );
+
+ /// The timeout value for this control. Normally defaulted to 250ms, but
+ /// certain controls (ie jog wheel) may want to override it.
+ virtual unsigned int in_use_timeout() { return _in_use_timeout; }
+
+ /// Keep track of the timeout so it can be updated with more incoming events
+ sigc::connection in_use_connection;
+
private:
int _id;
int _ordinal;
std::string _name;
Group & _group;
+ bool _in_use;
+ unsigned int _in_use_timeout;
};
std::ostream & operator << ( std::ostream & os, const Control & control );
@@ -218,18 +246,10 @@ class Fader : public Control
public:
Fader( int id, int ordinal, std::string name, Group & group )
: Control( id, ordinal, name, group )
- , _touch( false )
{
}
- bool touch() const { return _touch; }
-
- void touch( bool yn ) { _touch = yn; }
-
virtual type_t type() const { return type_fader; }
-
-private:
- bool _touch;
};
class Led : public Control
@@ -260,7 +280,7 @@ public:
}
virtual type_t type() const { return type_button; };
-
+
private:
Led _led;
};
@@ -296,6 +316,17 @@ private:
LedRing _led_ring;
};
+class Jog : public Pot
+{
+public:
+ Jog( int id, int ordinal, std::string name, Group & group )
+ : Pot( id, ordinal, name, group )
+ {
+ }
+
+ virtual bool is_jog() const { return true; }
+};
+
}
#endif
diff --git a/libs/surfaces/mackie/dummy_port.cc b/libs/surfaces/mackie/dummy_port.cc
new file mode 100644
index 0000000000..7654f8f987
--- /dev/null
+++ b/libs/surfaces/mackie/dummy_port.cc
@@ -0,0 +1,58 @@
+#include "dummy_port.h"
+
+#include "midi_byte_array.h"
+
+#include <midi++/port.h>
+#include <midi++/types.h>
+
+#include <iostream>
+
+using namespace Mackie;
+using namespace std;
+
+DummyPort::DummyPort()
+{
+}
+
+DummyPort::~DummyPort()
+{
+}
+
+
+void DummyPort::open()
+{
+ cout << "DummyPort::open" << endl;
+}
+
+
+void DummyPort::close()
+{
+ cout << "DummyPort::close" << endl;
+}
+
+
+MidiByteArray DummyPort::read()
+{
+ cout << "DummyPort::read" << endl;
+ return MidiByteArray();
+}
+
+
+void DummyPort::write( const MidiByteArray & mba )
+{
+ cout << "DummyPort::write " << mba << endl;
+}
+
+MidiByteArray empty_midi_byte_array;
+
+const MidiByteArray & DummyPort::sysex_hdr() const
+{
+ cout << "DummyPort::sysex_hdr" << endl;
+ return empty_midi_byte_array;
+}
+
+int DummyPort::strips() const
+{
+ cout << "DummyPort::strips" << endl;
+ return 0;
+}
diff --git a/libs/surfaces/mackie/dummy_port.h b/libs/surfaces/mackie/dummy_port.h
new file mode 100644
index 0000000000..4ed0a3043b
--- /dev/null
+++ b/libs/surfaces/mackie/dummy_port.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2008 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 dummy_port_h
+#define dummy_port_h
+
+#include "surface_port.h"
+
+#include "midi_byte_array.h"
+
+namespace MIDI {
+ class Port;
+}
+
+namespace Mackie
+{
+
+/**
+ A Dummy Port, to catch things that shouldn't be sent.
+*/
+class DummyPort : public SurfacePort
+{
+public:
+ DummyPort();
+ virtual ~DummyPort();
+
+ // when this is successful, active() should return true
+ virtual void open();
+
+ // subclasses should call this before doing their own close
+ virtual void close();
+
+ /// read bytes from the port. They'll either end up in the
+ /// parser, or if that's not active they'll be returned
+ virtual MidiByteArray read();
+
+ /// an easier way to output bytes via midi
+ virtual void write( const MidiByteArray & );
+
+ virtual const MidiByteArray & sysex_hdr() const;
+ virtual int strips() const;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/interface.cc b/libs/surfaces/mackie/interface.cc
index eda485b5d6..7872d47a78 100644
--- a/libs/surfaces/mackie/interface.cc
+++ b/libs/surfaces/mackie/interface.cc
@@ -64,9 +64,22 @@ new_mackie_protocol (ControlProtocolDescriptor* descriptor, Session* s)
void
delete_mackie_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
{
- delete cp;
+ try
+ {
+ delete cp;
+ }
+ catch ( exception & e )
+ {
+ cout << "Exception caught trying to destroy MackieControlProtocol: " << e.what() << endl;
+ }
}
+/**
+ This is called on startup to check whether the lib should be loaded.
+
+ So anything that can be changed in the UI should not be used here to
+ prevent loading of the lib.
+*/
bool
probe_mackie_protocol (ControlProtocolDescriptor* descriptor)
{
@@ -79,7 +92,11 @@ static ControlProtocolDescriptor mackie_descriptor = {
ptr : 0,
module : 0,
mandatory : 0,
- supports_feedback : true,
+ // actually, the surface does support feedback, but all this
+ // flag does is show a submenu on the UI, which is useless for the mackie
+ // because feedback is always on. In any case, who'd want to use the
+ // mcu without the motorised sliders doing their thing?
+ supports_feedback : false,
probe : probe_mackie_protocol,
initialize : new_mackie_protocol,
destroy : delete_mackie_protocol
diff --git a/libs/surfaces/mackie/mackie_button_handler.cc b/libs/surfaces/mackie/mackie_button_handler.cc
index f7ac2ab6d5..2db07beabd 100644
--- a/libs/surfaces/mackie/mackie_button_handler.cc
+++ b/libs/surfaces/mackie/mackie_button_handler.cc
@@ -689,3 +689,23 @@ LedState MackieButtonHandler::global_solo_release( Button & button )
{
return default_button_press( button );
}
+
+LedState MackieButtonHandler::drop_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::drop_release( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::save_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::save_release( Button & button )
+{
+ return default_button_press( button );
+}
diff --git a/libs/surfaces/mackie/mackie_button_handler.h b/libs/surfaces/mackie/mackie_button_handler.h
index ee4187c7ce..2e8bc649be 100644
--- a/libs/surfaces/mackie/mackie_button_handler.h
+++ b/libs/surfaces/mackie/mackie_button_handler.h
@@ -220,6 +220,12 @@ public:
virtual LedState global_solo_press( Button & );
virtual LedState global_solo_release( Button & );
+
+ virtual LedState drop_press( Button & );
+ virtual LedState drop_release( Button & );
+
+ virtual LedState save_press( Button & );
+ virtual LedState save_release( Button & );
};
}
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index f7886e078f..b29c26b0d3 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -14,7 +14,6 @@
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 <iostream>
@@ -22,6 +21,7 @@
#include <cmath>
#include <sstream>
#include <vector>
+#include <iomanip>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
@@ -38,12 +38,15 @@
#include <pbd/pthread_utils.h>
#include <pbd/error.h>
#include <pbd/memento_command.h>
+#include <pbd/convert.h>
#include <ardour/route.h>
#include <ardour/session.h>
#include <ardour/location.h>
#include <ardour/dB.h>
#include <ardour/panner.h>
+#include <ardour/tempo.h>
+#include <ardour/types.h>
#include "mackie_control_protocol.h"
@@ -68,27 +71,6 @@ using boost::shared_ptr;
MackieMidiBuilder builder;
-// Copied from tranzport_control_protocol.cc
-static inline double
-gain_to_slider_position (ARDOUR::gain_t g)
-{
- if (g == 0) return 0;
- return pow((6.0*log(g)/log(2.0)+192.0)/198.0, 8.0);
-}
-
-/*
- Copied from tranzport_control_protocol.cc
- TODO this seems to return slightly wrong values, namely
- with the UI slider at max, we get a 0.99something value.
-*/
-static inline ARDOUR::gain_t
-slider_position_to_gain (double pos)
-{
- /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
- if (pos == 0.0) return 0;
- return pow (2.0,(sqrt(sqrt(sqrt(pos)))*198.0-192.0)/6.0);
-}
-
MackieControlProtocol::MackieControlProtocol (Session& session)
: ControlProtocol (session, X_("Mackie"))
, _current_initial_bank( 0 )
@@ -98,15 +80,21 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
, _polling( true )
, pfd( 0 )
, nfds( 0 )
+ , _jog_wheel( *this )
+ , _timecode_type( ARDOUR::AnyTime::BBT )
{
- //cout << "MackieControlProtocol::MackieControlProtocol" << endl;
+#ifdef DEBUG
+ cout << "MackieControlProtocol::MackieControlProtocol" << endl;
+#endif
// will start reading from ports, as soon as there are some
pthread_create_and_store (X_("mackie monitor"), &thread, 0, _monitor_work, this);
}
MackieControlProtocol::~MackieControlProtocol()
{
- //cout << "~MackieControlProtocol::MackieControlProtocol" << endl;
+#ifdef DEBUG
+ cout << "~MackieControlProtocol::MackieControlProtocol" << endl;
+#endif
try
{
close();
@@ -119,7 +107,9 @@ MackieControlProtocol::~MackieControlProtocol()
{
cout << "~MackieControlProtocol caught unknown" << endl;
}
- //cout << "finished ~MackieControlProtocol::MackieControlProtocol" << endl;
+#ifdef DEBUG
+ cout << "finished ~MackieControlProtocol::MackieControlProtocol" << endl;
+#endif
}
Mackie::Surface & MackieControlProtocol::surface()
@@ -131,14 +121,28 @@ Mackie::Surface & MackieControlProtocol::surface()
return *_surface;
}
-const Mackie::MackiePort & MackieControlProtocol::mcu_port() const
+const Mackie::SurfacePort & MackieControlProtocol::mcu_port() const
{
- return dynamic_cast<const MackiePort &>( *_ports[0] );
+ if ( _ports.size() < 1 )
+ {
+ return _dummy_port;
+ }
+ else
+ {
+ return dynamic_cast<const MackiePort &>( *_ports[0] );
+ }
}
-Mackie::MackiePort & MackieControlProtocol::mcu_port()
+Mackie::SurfacePort & MackieControlProtocol::mcu_port()
{
- return dynamic_cast<const MackiePort &>( *_ports[0] );
+ if ( _ports.size() < 1 )
+ {
+ return _dummy_port;
+ }
+ else
+ {
+ return dynamic_cast<MackiePort &>( *_ports[0] );
+ }
}
// go to the previous track.
@@ -275,7 +279,9 @@ void MackieControlProtocol::switch_banks( int initial )
uint32_t end_pos = min( route_table.size(), sorted.size() );
Sorted::iterator it = sorted.begin() + _current_initial_bank;
Sorted::iterator end = sorted.begin() + _current_initial_bank + end_pos;
- //cout << "switch to " << _current_initial_bank << ", " << end_pos << endl;
+#ifdef DEBUG
+ cout << "switch to " << _current_initial_bank << ", " << end_pos << endl;
+#endif
// link routes to strips
uint32_t i = 0;
@@ -283,7 +289,9 @@ void MackieControlProtocol::switch_banks( int initial )
{
boost::shared_ptr<Route> route = *it;
Strip & strip = *surface().strips[i];
- //cout << "remote id " << route->remote_control_id() << " connecting " << route->name() << " to " << strip.name() << " with port " << port_for_id(i) << endl;
+#ifdef DEBUG
+ cout << "remote id " << route->remote_control_id() << " connecting " << route->name() << " to " << strip.name() << " with port " << port_for_id(i) << endl;
+#endif
route_table[i] = route;
RouteSignal * rs = new RouteSignal( *route, *this, strip, port_for_id(i) );
route_signals.push_back( rs );
@@ -297,51 +305,28 @@ void MackieControlProtocol::switch_banks( int initial )
{
Strip & strip = *surface().strips[i];
// send zero for this strip
- port_for_id(i).write( builder.zero_strip( strip ) );
+ MackiePort & port = port_for_id(i);
+ port.write( builder.zero_strip( port, strip ) );
}
}
// display the current start bank.
- if ( mcu_port().emulation() == MackiePort::bcf2000 )
- {
- if ( _current_initial_bank == 0 )
- {
- // send Ar. to 2-char display on the master
- mcu_port().write( builder.two_char_display( "Ar", ".." ) );
- }
- else
- {
- // write the current first remote_id to the 2-char display
- mcu_port().write( builder.two_char_display( _current_initial_bank ) );
- }
- }
+ surface().display_bank_start( mcu_port(), builder, _current_initial_bank );
}
void MackieControlProtocol::zero_all()
{
- // TODO turn off 55-char and SMPTE displays
-
- if ( mcu_port().emulation() == MackiePort::bcf2000 )
- {
- // clear 2-char display
- mcu_port().write( builder.two_char_display( "LC" ) );
- }
+ // TODO turn off SMPTE displays
// zero all strips
for ( Surface::Strips::iterator it = surface().strips.begin(); it != surface().strips.end(); ++it )
{
- port_for_id( (*it)->index() ).write( builder.zero_strip( **it ) );
+ MackiePort & port = port_for_id( (*it)->index() );
+ port.write( builder.zero_strip( port, **it ) );
}
// and the master strip
- mcu_port().write( builder.zero_strip( master_strip() ) );
-
- // and the led ring for the master strip, in bcf mode
- if ( mcu_port().emulation() == MackiePort::bcf2000 )
- {
- Control & control = *surface().controls_by_name["jog"];
- mcu_port().write( builder.build_led_ring( dynamic_cast<Pot &>( control ), off ) );
- }
+ mcu_port().write( builder.zero_strip( dynamic_cast<MackiePort&>( mcu_port() ), master_strip() ) );
// turn off global buttons and leds
// global buttons are only ever on mcu_port, so we don't have
@@ -354,9 +339,12 @@ void MackieControlProtocol::zero_all()
mcu_port().write( builder.zero_control( control ) );
}
}
+
+ // any hardware-specific stuff
+ surface().zero_all( mcu_port(), builder );
}
-int MackieControlProtocol::set_active (bool yn)
+int MackieControlProtocol::set_active( bool yn )
{
if ( yn != _active )
{
@@ -466,7 +454,7 @@ bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState
if ( control.name() == "fader_touch" )
{
state = bs == press;
- control.strip().gain().touch( state );
+ control.strip().gain().in_use( state );
}
return state;
@@ -474,28 +462,50 @@ bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState
void MackieControlProtocol::update_led( Mackie::Button & button, Mackie::LedState ls )
{
- MackiePort * port = 0;
- if ( button.group().is_strip() )
+ if ( ls != none )
{
- if ( button.group().is_master() )
+ SurfacePort * port = 0;
+ if ( button.group().is_strip() )
{
- port = &mcu_port();
+ if ( button.group().is_master() )
+ {
+ port = &mcu_port();
+ }
+ else
+ {
+ port = &port_for_id( dynamic_cast<const Strip&>( button.group() ).index() );
+ }
}
else
{
- port = &port_for_id( dynamic_cast<const Strip&>( button.group() ).index() );
+ port = &mcu_port();
}
+ port->write( builder.build_led( button, ls ) );
}
- else
+}
+
+void MackieControlProtocol::update_smpte_beats_led()
+{
+ switch ( _timecode_type )
{
- port = &mcu_port();
+ case ARDOUR::AnyTime::BBT:
+ update_global_led( "beats", on );
+ update_global_led( "smpte", off );
+ break;
+ case ARDOUR::AnyTime::SMPTE:
+ update_global_led( "smpte", on );
+ update_global_led( "beats", off );
+ break;
+ default:
+ ostringstream os;
+ os << "Unknown Anytime::Type " << _timecode_type;
+ throw runtime_error( os.str() );
}
- if ( ls != none ) port->write( builder.build_led( button, ls ) );
}
void MackieControlProtocol::update_global_button( const string & name, LedState ls )
{
- if ( surface().controls_by_name.find( name ) !=surface().controls_by_name.end() )
+ if ( surface().controls_by_name.find( name ) != surface().controls_by_name.end() )
{
Button * button = dynamic_cast<Button*>( surface().controls_by_name[name] );
mcu_port().write( builder.build_led( button->led(), ls ) );
@@ -505,7 +515,22 @@ void MackieControlProtocol::update_global_button( const string & name, LedState
#ifdef DEBUG
cout << "Button " << name << " not found" << endl;
#endif
- }
+ }
+}
+
+void MackieControlProtocol::update_global_led( const string & name, LedState ls )
+{
+ if ( surface().controls_by_name.find( name ) != surface().controls_by_name.end() )
+ {
+ Led * led = dynamic_cast<Led*>( surface().controls_by_name[name] );
+ mcu_port().write( builder.build_led( *led, ls ) );
+ }
+ else
+ {
+#ifdef DEBUG
+ cout << "Led " << name << " not found" << endl;
+#endif
+ }
}
// send messages to surface to set controls to correct values
@@ -523,9 +548,13 @@ void MackieControlProtocol::update_surface()
// update strip from route
master_route_signal->notify_all();
+ // sometimes the jog wheel is a pot
+ surface().blank_jog_ring( mcu_port(), builder );
+
// update global buttons and displays
notify_record_state_changed();
notify_transport_state_changed();
+ update_smpte_beats_led();
}
}
@@ -553,31 +582,47 @@ void MackieControlProtocol::connect_session_signals()
void MackieControlProtocol::add_port( MIDI::Port & midi_port, int number )
{
- MackiePort * sport = new MackiePort( *this, midi_port, number );
- _ports.push_back( sport );
-
- connections_back = sport->init_event.connect(
- sigc::bind (
- mem_fun (*this, &MackieControlProtocol::handle_port_init)
- , sport
- )
- );
-
- connections_back = sport->active_event.connect(
- sigc::bind (
- mem_fun (*this, &MackieControlProtocol::handle_port_active)
- , sport
- )
- );
-
- connections_back = sport->inactive_event.connect(
- sigc::bind (
- mem_fun (*this, &MackieControlProtocol::handle_port_inactive)
- , sport
- )
- );
-
- _ports_changed = true;
+#ifdef DEBUG
+ cout << "add port " << midi_port.name() << ", " << midi_port.device() << ", " << midi_port.type() << endl;
+ cout << "MIDI::Port::ALSA_Sequencer " << MIDI::Port::ALSA_Sequencer << endl;
+ cout << "MIDI::Port::Unknown " << MIDI::Port::Unknown << endl;
+#endif
+ if ( string( midi_port.device() ) == string( "ardour" ) )
+ {
+ throw MackieControlException( "The Mackie MCU driver will not use a port with device=ardour" );
+ }
+ else if ( midi_port.type() == MIDI::Port::ALSA_Sequencer )
+ {
+ throw MackieControlException( "alsa/sequencer ports don't work with the Mackie MCU driver right now" );
+ }
+ else
+ {
+ MackiePort * sport = new MackiePort( *this, midi_port, number );
+ _ports.push_back( sport );
+
+ connections_back = sport->init_event.connect(
+ sigc::bind (
+ mem_fun (*this, &MackieControlProtocol::handle_port_init)
+ , sport
+ )
+ );
+
+ connections_back = sport->active_event.connect(
+ sigc::bind (
+ mem_fun (*this, &MackieControlProtocol::handle_port_active)
+ , sport
+ )
+ );
+
+ connections_back = sport->inactive_event.connect(
+ sigc::bind (
+ mem_fun (*this, &MackieControlProtocol::handle_port_inactive)
+ , sport
+ )
+ );
+
+ _ports_changed = true;
+ }
}
void MackieControlProtocol::create_ports()
@@ -636,15 +681,23 @@ void MackieControlProtocol::initialize_surface()
set_route_table_size( strips );
- switch ( mcu_port().emulation() )
+ // TODO same as code in mackie_port.cc
+ string emulation = ARDOUR::Config->get_mackie_emulation();
+ if ( emulation == "bcf" )
{
- case MackiePort::bcf2000: _surface = new BcfSurface( strips ); break;
- case MackiePort::mackie: _surface = new MackieSurface( strips ); break;
- default:
- ostringstream os;
- os << "no Surface class found for emulation: " << mcu_port().emulation();
- throw MackieControlException( os.str() );
+ _surface = new BcfSurface( strips );
+ }
+ else if ( emulation == "mcu" )
+ {
+ _surface = new MackieSurface( strips );
+ }
+ else
+ {
+ ostringstream os;
+ os << "no Surface class found for emulation: " << emulation;
+ throw MackieControlException( os.str() );
}
+
_surface->init();
// Connect events. Must be after route table otherwise there will be trouble
@@ -656,6 +709,12 @@ void MackieControlProtocol::initialize_surface()
void MackieControlProtocol::close()
{
+ // stop polling, and wait for it...
+ // must be before other shutdown otherwise polling loop
+ // calls methods on objects that are deleted
+ _polling = false;
+ pthread_join( thread, 0 );
+
// TODO disconnect port active/inactive signals
// Or at least put a lock here
@@ -713,10 +772,6 @@ void MackieControlProtocol::close()
_surface = 0;
}
- // stop polling, and wait for it...
- _polling = false;
- pthread_join( thread, 0 );
-
// shut down MackiePorts
for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
{
@@ -737,7 +792,9 @@ void* MackieControlProtocol::_monitor_work (void* arg)
XMLNode & MackieControlProtocol::get_state()
{
- //cout << "MackieControlProtocol::get_state" << endl;
+#ifdef DEBUG
+ cout << "MackieControlProtocol::get_state" << endl;
+#endif
// add name of protocol
XMLNode* node = new XMLNode( X_("Protocol") );
@@ -753,7 +810,9 @@ XMLNode & MackieControlProtocol::get_state()
int MackieControlProtocol::set_state( const XMLNode & node )
{
- //cout << "MackieControlProtocol::set_state: active " << _active << endl;
+#ifdef DEBUG
+ cout << "MackieControlProtocol::set_state: active " << _active << endl;
+#endif
int retval = 0;
// fetch current bank
@@ -780,7 +839,7 @@ int MackieControlProtocol::set_state( const XMLNode & node )
void MackieControlProtocol::handle_control_event( SurfacePort & port, Control & control, const ControlState & state )
{
- uint32_t index = control.ordinal() - 1 + ( port.number() * port.strips() );
+ // find the route for the control, if there is one
boost::shared_ptr<Route> route;
if ( control.group().is_strip() )
{
@@ -788,10 +847,14 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control &
{
route = master_route();
}
- else if ( index < route_table.size() )
- route = route_table[index];
else
- cerr << "Warning: index is " << index << " which is not in the route table, size: " << route_table.size() << endl;
+ {
+ uint32_t index = control.ordinal() - 1 + ( port.number() * port.strips() );
+ if ( index < route_table.size() )
+ route = route_table[index];
+ else
+ cerr << "Warning: index is " << index << " which is not in the route table, size: " << route_table.size() << endl;
+ }
}
// This handles control element events from the surface
@@ -800,30 +863,17 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control &
switch ( control.type() )
{
case Control::type_fader:
- if ( control.group().is_strip() )
+ // find the route in the route table for the id
+ // if the route isn't available, skip it
+ // at which point the fader should just reset itself
+ if ( route != 0 )
{
- // find the route in the route table for the id
- // if the route isn't available, skip it
- // at which point the fader should just reset itself
- if ( route != 0 )
- {
- route->set_gain( slider_position_to_gain( state.pos ), this );
-
- // must echo bytes back to slider now, because
- // the notifier only works if the fader is not being
- // touched. Which it is if we're getting input.
- port.write( builder.build_fader( (Fader&)control, state.pos ) );
- }
- }
- else
- {
- // master fader
- boost::shared_ptr<Route> route = master_route();
- if ( route )
- {
- route->set_gain( slider_position_to_gain( state.pos ), this );
- port.write( builder.build_fader( (Fader&)control, state.pos ) );
- }
+ route->gain_control()->set_value( state.pos );
+
+ // must echo bytes back to slider now, because
+ // the notifier only works if the fader is not being
+ // touched. Which it is if we're getting input.
+ port.write( builder.build_fader( (Fader&)control, state.pos ) );
}
break;
@@ -845,9 +895,10 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control &
else if ( control.group().is_master() )
{
// master fader touch
- boost::shared_ptr<Route> route = master_route();
- if ( route )
+ if ( route != 0 )
+ {
handle_strip_button( control, state.button_state, route );
+ }
}
else
{
@@ -862,19 +913,21 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control &
{
if ( route != 0 )
{
- if ( route->panner().npanners() == 1 )
+ // pan for mono input routes, or stereo linked panners
+ if ( route->panner().npanners() == 1 || ( route->panner().npanners() == 2 && route->panner().linked() ) )
{
// assume pan for now
- float xpos = route->panner().pan_control(0)->get_value ();
+ float xpos;
+ route->panner().streampanner (0).get_effective_position (xpos);
// calculate new value, and trim
- xpos += state.delta;
+ xpos += state.delta * state.sign;
if ( xpos > 1.0 )
xpos = 1.0;
else if ( xpos < 0.0 )
xpos = 0.0;
- route->panner().pan_control(0)->set_value( xpos );
+ route->panner().streampanner (0).set_position( xpos );
}
}
else
@@ -885,29 +938,13 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control &
}
else
{
- if ( control.name() == "jog" )
+ if ( control.is_jog() )
{
- // TODO use current snap-to setting?
- long delta = state.ticks * 1000;
- nframes_t next = session->transport_frame() + delta;
- if ( delta < 0 && session->transport_frame() < (nframes_t) abs( delta ) )
- {
- next = session->current_start_frame();
- }
- else if ( next > session->current_end_frame() )
- {
- next = session->current_end_frame();
- }
-
- // doesn't work very well
- session->request_locate( next, session->transport_rolling() );
-
- // turn off the led ring, for bcf emulation mode
- port.write( builder.build_led_ring( dynamic_cast<Pot &>( control ), off ) );
+ _jog_wheel.jog_event( port, control, state );
}
else
{
- cout << "external controller" << state.ticks << endl;
+ cout << "external controller" << state.ticks * state.sign << endl;
}
}
break;
@@ -963,14 +1000,35 @@ void MackieControlProtocol::notify_record_enable_changed( RouteSignal * route_si
}
}
-void MackieControlProtocol::notify_gain_changed( RouteSignal * route_signal )
+void MackieControlProtocol::notify_active_changed( RouteSignal * route_signal )
+{
+ try
+ {
+#ifdef DEBUG
+ cout << "MackieControlProtocol::notify_active_changed" << endl;
+#endif
+ refresh_current_bank();
+ }
+ catch( exception & e )
+ {
+ cout << e.what() << endl;
+ }
+}
+
+void MackieControlProtocol::notify_gain_changed( RouteSignal * route_signal, bool force_update )
{
try
{
Fader & fader = route_signal->strip().gain();
- if ( !fader.touch() )
+ if ( !fader.in_use() )
{
- route_signal->port().write( builder.build_fader( fader, gain_to_slider_position( route_signal->route().effective_gain() ) ) );
+ float gain_value = route_signal->route().gain_control()->get_value();
+ // check that something has actually changed
+ if ( force_update || gain_value != route_signal->last_gain_written() )
+ {
+ route_signal->port().write( builder.build_fader( fader, gain_value ) );
+ route_signal->last_gain_written( gain_value );
+ }
}
}
catch( exception & e )
@@ -983,7 +1041,25 @@ void MackieControlProtocol::notify_name_changed( RouteSignal * route_signal )
{
try
{
- // TODO implement MackieControlProtocol::notify_name_changed
+ Strip & strip = route_signal->strip();
+ if ( !strip.is_master() )
+ {
+ string line1;
+ string fullname = route_signal->route().name();
+
+ if ( fullname.length() <= 6 )
+ {
+ line1 = fullname;
+ }
+ else
+ {
+ line1 = PBD::short_version( fullname, 6 );
+ }
+
+ SurfacePort & port = route_signal->port();
+ port.write( builder.strip_display( port, strip, 0, line1 ) );
+ port.write( builder.strip_display_blank( port, strip, 1 ) );
+ }
}
catch( exception & e )
{
@@ -991,17 +1067,27 @@ void MackieControlProtocol::notify_name_changed( RouteSignal * route_signal )
}
}
-// TODO deal with > 1 channel being panned
-void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal )
+void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal, bool force_update )
{
try
{
Pot & pot = route_signal->strip().vpot();
-
- if ( route_signal->route().panner().npanners() == 1 )
+ const Panner & panner = route_signal->route().panner();
+ if ( panner.npanners() == 1 || ( panner.npanners() == 2 && panner.linked() ) )
{
- float pos = route_signal->route().panner().pan_control(0)->get_value();
- route_signal->port().write( builder.build_led_ring( pot, ControlState( on, pos ) ) );
+ float pos;
+ route_signal->route().panner().streampanner(0).get_effective_position( pos );
+
+ // cache the MidiByteArray here, because the mackie led control is much lower
+ // resolution than the panner control. So we save lots of byte
+ // sends in spite of more work on the comparison
+ MidiByteArray bytes = builder.build_led_ring( pot, ControlState( on, pos ), MackieMidiBuilder::midi_pot_mode_dot );
+ // check that something has actually changed
+ if ( force_update || bytes != route_signal->last_pan_written() )
+ {
+ route_signal->port().write( bytes );
+ route_signal->last_pan_written( bytes );
+ }
}
else
{
@@ -1017,39 +1103,18 @@ void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal )
// TODO handle plugin automation polling
void MackieControlProtocol::update_automation( RouteSignal & rs )
{
- ARDOUR::AutoState gain_state = rs.route().gain_control()->alist()->automation_state();
+ ARDOUR::AutoState gain_state = rs.route().gain_control()->automation_state();
if ( gain_state == Touch || gain_state == Play )
{
- notify_gain_changed( &rs );
+ notify_gain_changed( &rs, false );
}
ARDOUR::AutoState panner_state = rs.route().panner().automation_state();
if ( panner_state == Touch || panner_state == Play )
{
- notify_panner_changed( &rs );
- }
-}
-
-void MackieControlProtocol::poll_automation ()
-{
- if ( _active && _automation_last.elapsed() >= 20 )
- {
- // do all currently mapped routes
- for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it )
- {
- update_automation( **it );
- }
-
- // and the master strip
- if ( master_route_signal != 0 )
- {
- update_automation( *master_route_signal );
- }
-
- update_timecode_display();
-
- _automation_last.start();
+ notify_panner_changed( &rs, false );
}
+ _automation_last.start();
}
string MackieControlProtocol::format_bbt_timecode( nframes_t now_frame )
@@ -1130,6 +1195,28 @@ void MackieControlProtocol::update_timecode_display()
}
}
+void MackieControlProtocol::poll_session_data()
+{
+ if ( _active && _automation_last.elapsed() >= 20 )
+ {
+ // do all currently mapped routes
+ for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it )
+ {
+ update_automation( **it );
+ }
+
+ // and the master strip
+ if ( master_route_signal != 0 )
+ {
+ update_automation( *master_route_signal );
+ }
+
+ update_timecode_display();
+
+ _automation_last.start();
+ }
+}
+
/////////////////////////////////////
// Transport Buttons
/////////////////////////////////////
@@ -1137,10 +1224,28 @@ void MackieControlProtocol::update_timecode_display()
LedState MackieControlProtocol::frm_left_press( Button & button )
{
// can use first_mark_before/after as well
+ unsigned long elapsed = _frm_left_last.restart();
+
Location * loc = session->locations()->first_location_before (
session->transport_frame()
);
- if ( loc != 0 ) session->request_locate( loc->start(), session->transport_rolling() );
+
+ // allow a quick double to go past a previous mark
+ if ( session->transport_rolling() && elapsed < 500 && loc != 0 )
+ {
+ Location * loc_two_back = session->locations()->first_location_before ( loc->start() );
+ if ( loc_two_back != 0 )
+ {
+ loc = loc_two_back;
+ }
+ }
+
+ // move to the location, if it's valid
+ if ( loc != 0 )
+ {
+ session->request_locate( loc->start(), session->transport_rolling() );
+ }
+
return on;
}
@@ -1210,12 +1315,16 @@ LedState MackieControlProtocol::record_release( Button & button )
LedState MackieControlProtocol::rewind_press( Button & button )
{
- session->request_transport_speed( -4.0 );
+ _jog_wheel.push( JogWheel::speed );
+ _jog_wheel.transport_direction( -1 );
+ session->request_transport_speed( -_jog_wheel.transport_speed() );
return on;
}
LedState MackieControlProtocol::rewind_release( Button & button )
{
+ _jog_wheel.pop();
+ _jog_wheel.transport_direction( 0 );
if ( _transport_previously_rolling )
session->request_transport_speed( 1.0 );
else
@@ -1225,12 +1334,16 @@ LedState MackieControlProtocol::rewind_release( Button & button )
LedState MackieControlProtocol::ffwd_press( Button & button )
{
- session->request_transport_speed( 4.0 );
+ _jog_wheel.push( JogWheel::speed );
+ _jog_wheel.transport_direction( 1 );
+ session->request_transport_speed( _jog_wheel.transport_speed() );
return on;
}
LedState MackieControlProtocol::ffwd_release( Button & button )
{
+ _jog_wheel.pop();
+ _jog_wheel.transport_direction( 0 );
if ( _transport_previously_rolling )
session->request_transport_speed( 1.0 );
else
@@ -1238,6 +1351,87 @@ LedState MackieControlProtocol::ffwd_release( Button & button )
return off;
}
+LedState MackieControlProtocol::loop_press( Button & button )
+{
+ session->request_play_loop( !session->get_play_loop() );
+ return on;
+}
+
+LedState MackieControlProtocol::loop_release( Button & button )
+{
+ return session->get_play_loop();
+}
+
+LedState MackieControlProtocol::punch_in_press( Button & button )
+{
+ bool state = !Config->get_punch_in();
+ Config->set_punch_in( state );
+ return state;
+}
+
+LedState MackieControlProtocol::punch_in_release( Button & button )
+{
+ return Config->get_punch_in();
+}
+
+LedState MackieControlProtocol::punch_out_press( Button & button )
+{
+ bool state = !Config->get_punch_out();
+ Config->set_punch_out( state );
+ return state;
+}
+
+LedState MackieControlProtocol::punch_out_release( Button & button )
+{
+ return Config->get_punch_out();
+}
+
+LedState MackieControlProtocol::home_press( Button & button )
+{
+ session->goto_start();
+ return on;
+}
+
+LedState MackieControlProtocol::home_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::end_press( Button & button )
+{
+ session->goto_end();
+ return on;
+}
+
+LedState MackieControlProtocol::end_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::clicking_press( Button & button )
+{
+ bool state = !Config->get_clicking();
+ Config->set_clicking( state );
+ return state;
+}
+
+LedState MackieControlProtocol::clicking_release( Button & button )
+{
+ return Config->get_clicking();
+}
+
+LedState MackieControlProtocol::global_solo_press( Button & button )
+{
+ bool state = !session->soloing();
+ session->set_all_solo ( state );
+ return state;
+}
+
+LedState MackieControlProtocol::global_solo_release( Button & button )
+{
+ return session->soloing();
+}
+
///////////////////////////////////////////
// Session signals
///////////////////////////////////////////
@@ -1333,87 +1527,6 @@ void MackieControlProtocol::notify_transport_state_changed()
mcu_port().write( builder.build_led( *rec, record_release( *rec ) ) );
}
-LedState MackieControlProtocol::loop_press( Button & button )
-{
- session->request_play_loop( !session->get_play_loop() );
- return on;
-}
-
-LedState MackieControlProtocol::loop_release( Button & button )
-{
- return session->get_play_loop();
-}
-
-LedState MackieControlProtocol::punch_in_press( Button & button )
-{
- bool state = !Config->get_punch_in();
- Config->set_punch_in( state );
- return state;
-}
-
-LedState MackieControlProtocol::punch_in_release( Button & button )
-{
- return Config->get_punch_in();
-}
-
-LedState MackieControlProtocol::punch_out_press( Button & button )
-{
- bool state = !Config->get_punch_out();
- Config->set_punch_out( state );
- return state;
-}
-
-LedState MackieControlProtocol::punch_out_release( Button & button )
-{
- return Config->get_punch_out();
-}
-
-LedState MackieControlProtocol::home_press( Button & button )
-{
- session->goto_start();
- return on;
-}
-
-LedState MackieControlProtocol::home_release( Button & button )
-{
- return off;
-}
-
-LedState MackieControlProtocol::end_press( Button & button )
-{
- session->goto_end();
- return on;
-}
-
-LedState MackieControlProtocol::end_release( Button & button )
-{
- return off;
-}
-
-LedState MackieControlProtocol::clicking_press( Button & button )
-{
- bool state = !Config->get_clicking();
- Config->set_clicking( state );
- return state;
-}
-
-LedState MackieControlProtocol::clicking_release( Button & button )
-{
- return Config->get_clicking();
-}
-
-LedState MackieControlProtocol::global_solo_press( Button & button )
-{
- bool state = !session->soloing();
- session->set_all_solo ( state );
- return state;
-}
-
-LedState MackieControlProtocol::global_solo_release( Button & button )
-{
- return session->soloing();
-}
-
/////////////////////////////////////
// Bank Switching
/////////////////////////////////////
@@ -1530,3 +1643,96 @@ LedState MackieControlProtocol::marker_release( Button & button )
{
return off;
}
+
+void jog_wheel_state_display( JogWheel::State state, SurfacePort & port )
+{
+ switch( state )
+ {
+ case JogWheel::zoom: port.write( builder.two_char_display( "Zm" ) ); break;
+ case JogWheel::scroll: port.write( builder.two_char_display( "Sc" ) ); break;
+ case JogWheel::scrub: port.write( builder.two_char_display( "Sb" ) ); break;
+ case JogWheel::shuttle: port.write( builder.two_char_display( "Sh" ) ); break;
+ case JogWheel::speed: port.write( builder.two_char_display( "Sp" ) ); break;
+ case JogWheel::select: port.write( builder.two_char_display( "Se" ) ); break;
+ }
+}
+
+Mackie::LedState MackieControlProtocol::zoom_press( Mackie::Button & )
+{
+ _jog_wheel.zoom_state_toggle();
+ update_global_button( "scrub", _jog_wheel.jog_wheel_state() == JogWheel::scrub );
+ jog_wheel_state_display( _jog_wheel.jog_wheel_state(), mcu_port() );
+ return _jog_wheel.jog_wheel_state() == JogWheel::zoom;
+}
+
+Mackie::LedState MackieControlProtocol::zoom_release( Mackie::Button & )
+{
+ return _jog_wheel.jog_wheel_state() == JogWheel::zoom;
+}
+
+Mackie::LedState MackieControlProtocol::scrub_press( Mackie::Button & )
+{
+ _jog_wheel.scrub_state_cycle();
+ update_global_button( "zoom", _jog_wheel.jog_wheel_state() == JogWheel::zoom );
+ jog_wheel_state_display( _jog_wheel.jog_wheel_state(), mcu_port() );
+ return
+ _jog_wheel.jog_wheel_state() == JogWheel::scrub
+ ||
+ _jog_wheel.jog_wheel_state() == JogWheel::shuttle
+ ;
+}
+
+Mackie::LedState MackieControlProtocol::scrub_release( Mackie::Button & )
+{
+ return
+ _jog_wheel.jog_wheel_state() == JogWheel::scrub
+ ||
+ _jog_wheel.jog_wheel_state() == JogWheel::shuttle
+ ;
+}
+
+LedState MackieControlProtocol::drop_press( Button & button )
+{
+ session->remove_last_capture();
+ return on;
+}
+
+LedState MackieControlProtocol::drop_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::save_press( Button & button )
+{
+ session->save_state( "" );
+ return on;
+}
+
+LedState MackieControlProtocol::save_release( Button & button )
+{
+ return off;
+}
+
+LedState MackieControlProtocol::smpte_beats_press( Button & )
+{
+ switch ( _timecode_type )
+ {
+ case ARDOUR::AnyTime::BBT:
+ _timecode_type = ARDOUR::AnyTime::SMPTE;
+ break;
+ case ARDOUR::AnyTime::SMPTE:
+ _timecode_type = ARDOUR::AnyTime::BBT;
+ break;
+ default:
+ ostringstream os;
+ os << "Unknown Anytime::Type " << _timecode_type;
+ throw runtime_error( os.str() );
+ }
+ update_smpte_beats_led();
+ return on;
+}
+
+LedState MackieControlProtocol::smpte_beats_release( Button & )
+{
+ return off;
+}
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
index 735a2c88bd..4e4a76f977 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.h
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -32,9 +32,12 @@
#include <control_protocol/control_protocol.h>
#include "midi_byte_array.h"
#include "controls.h"
+#include "dummy_port.h"
#include "route_signal.h"
#include "mackie_button_handler.h"
#include "mackie_port.h"
+#include "mackie_jog_wheel.h"
+#include "timer.h"
namespace MIDI {
class Port;
@@ -93,14 +96,16 @@ class MackieControlProtocol
/// Signal handler for Route::record_enable_changed
void notify_record_enable_changed( Mackie::RouteSignal * );
/// Signal handler for Route::gain_changed ( from IO )
- void notify_gain_changed( Mackie::RouteSignal * );
+ void notify_gain_changed( Mackie::RouteSignal *, bool force_update = true );
/// Signal handler for Route::name_change
void notify_name_changed( Mackie::RouteSignal * );
/// Signal handler from Panner::Change
- void notify_panner_changed( Mackie::RouteSignal * );
+ void notify_panner_changed( Mackie::RouteSignal *, bool force_update = true );
/// Signal handler for new routes added
void notify_route_added( ARDOUR::Session::RouteList & );
-
+ /// Signal handler for Route::active_changed
+ void notify_active_changed( Mackie::RouteSignal * );
+
void notify_remote_id_changed();
/// rebuild the current bank. Called on route added/removed and
@@ -116,12 +121,15 @@ class MackieControlProtocol
void notify_parameter_changed( const char * );
void notify_solo_active_changed( bool );
- // this is called to generate the midi to send in response to
- // a button press.
+ /// Turn smpte on and beats off, or vice versa, depending
+ /// on state of _timecode_type
+ void update_smpte_beats_led();
+
+ /// this is called to generate the midi to send in response to a button press.
void update_led( Mackie::Button & button, Mackie::LedState );
- // calls update_led, but looks up the button by name
void update_global_button( const std::string & name, Mackie::LedState );
+ void update_global_led( const std::string & name, Mackie::LedState );
// transport button handler methods from MackieButtonHandler
virtual Mackie::LedState frm_left_press( Mackie::Button & );
@@ -183,6 +191,28 @@ class MackieControlProtocol
virtual Mackie::LedState marker_press( Mackie::Button & );
virtual Mackie::LedState marker_release( Mackie::Button & );
+ virtual Mackie::LedState drop_press( Mackie::Button & );
+ virtual Mackie::LedState drop_release( Mackie::Button & );
+
+ virtual Mackie::LedState save_press( Mackie::Button & );
+ virtual Mackie::LedState save_release( Mackie::Button & );
+
+ virtual Mackie::LedState smpte_beats_press( Mackie::Button & );
+ virtual Mackie::LedState smpte_beats_release( Mackie::Button & );
+
+ // jog wheel states
+ virtual Mackie::LedState zoom_press( Mackie::Button & );
+ virtual Mackie::LedState zoom_release( Mackie::Button & );
+
+ virtual Mackie::LedState scrub_press( Mackie::Button & );
+ virtual Mackie::LedState scrub_release( Mackie::Button & );
+
+ /// This is the main MCU port, ie not an extender port
+ /// Only for use by JogWheel
+ const Mackie::SurfacePort & mcu_port() const;
+ Mackie::SurfacePort & mcu_port();
+ ARDOUR::Session & get_session() { return *session; }
+
protected:
// create instances of MackiePort, depending on what's found in ardour.rc
void create_ports();
@@ -221,10 +251,6 @@ class MackieControlProtocol
// delete all RouteSignal objects connecting Routes to Strips
void clear_route_signals();
- /// This is the main MCU port, ie not an extender port
- const Mackie::MackiePort & mcu_port() const;
- Mackie::MackiePort & mcu_port();
-
typedef std::vector<Mackie::RouteSignal*> RouteSignals;
RouteSignals route_signals;
@@ -260,14 +286,17 @@ class MackieControlProtocol
automation from the currently active routes and
timecode displays.
*/
- void poll_automation ();
+ void poll_session_data();
// called from poll_automation to figure out which automations need to be sent
void update_automation( Mackie::RouteSignal & );
-
+
// also called from poll_automation to update timecode display
void update_timecode_display();
+ std::string format_bbt_timecode( nframes_t now_frame );
+ std::string format_smpte_timecode( nframes_t now_frame );
+
/**
notification that the port is about to start it's init sequence.
We must make sure that before this exits, the port is being polled
@@ -293,6 +322,9 @@ class MackieControlProtocol
typedef vector<Mackie::MackiePort*> MackiePorts;
MackiePorts _ports;
+ /// Sometimes the real port goes away, and we want to contain the breakage
+ Mackie::DummyPort _dummy_port;
+
// the thread that polls the ports for incoming midi data
pthread_t thread;
@@ -321,6 +353,20 @@ class MackieControlProtocol
int nfds;
bool _transport_previously_rolling;
+
+ // timer for two quick marker left presses
+ Mackie::Timer _frm_left_last;
+
+ Mackie::JogWheel _jog_wheel;
+
+ // Timer for controlling midi bandwidth used by automation polls
+ Mackie::Timer _automation_last;
+
+ // last written timecode string
+ std::string _timecode_last;
+
+ // Which timecode are we displaying? BBT or SMPTE
+ ARDOUR::AnyTime::Type _timecode_type;
};
#endif // ardour_mackie_control_protocol_h
diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
index cd95551f70..88c00ed6eb 100644
--- a/libs/surfaces/mackie/mackie_control_protocol_poll.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
@@ -28,7 +28,15 @@ const char * MackieControlProtocol::default_port_name = "mcu";
bool MackieControlProtocol::probe()
{
- return MIDI::Manager::instance()->port( default_port_name ) != 0;
+ if ( MIDI::Manager::instance()->port( default_port_name ) == 0 )
+ {
+ error << "No port called mcu. Add it to ardour.rc." << endmsg;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
}
void * MackieControlProtocol::monitor_work()
@@ -52,8 +60,8 @@ void * MackieControlProtocol::monitor_work()
update_ports();
}
}
- // poll for automation data from the routes
- poll_automation();
+ // poll for session data that needs to go to the unit
+ poll_session_data();
}
catch ( exception & e )
{
@@ -71,30 +79,51 @@ void * MackieControlProtocol::monitor_work()
void MackieControlProtocol::update_ports()
{
+#ifdef DEBUG
+ cout << "MackieControlProtocol::update_ports" << endl;
+#endif
if ( _ports_changed )
{
Glib::Mutex::Lock ul( update_mutex );
// yes, this is a double-test locking paradigm, or whatever it's called
// because we don't *always* need to acquire the lock for the first test
+#ifdef DEBUG
+ cout << "MackieControlProtocol::update_ports lock acquired" << endl;
+#endif
if ( _ports_changed )
{
// create new pollfd structures
- if ( pfd != 0 ) delete[] pfd;
- // TODO This might be a memory leak. How does thread cancellation cleanup work?
+ if ( pfd != 0 )
+ {
+ delete[] pfd;
+ pfd = 0;
+ }
pfd = new pollfd[_ports.size()];
+#ifdef DEBUG
+ cout << "pfd: " << pfd << endl;
+#endif
nfds = 0;
-
for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
{
- //cout << "adding port " << (*it)->port().name() << " to pollfd" << endl;
+ // add the port any handler
+ (*it)->connect_any();
+#ifdef DEBUG
+ cout << "adding pollfd for port " << (*it)->port().name() << " to pollfd " << nfds << endl;
+#endif
pfd[nfds].fd = (*it)->port().selectable();
pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
++nfds;
}
_ports_changed = false;
}
+#ifdef DEBUG
+ cout << "MackieControlProtocol::update_ports signal" << endl;
+#endif
update_cond.signal();
}
+#ifdef DEBUG
+ cout << "MackieControlProtocol::update_ports finish" << endl;
+#endif
}
void MackieControlProtocol::read_ports()
@@ -127,12 +156,14 @@ bool MackieControlProtocol::poll_ports()
if ( nfds < 1 )
{
lock.release();
- //cout << "poll_ports no ports" << endl;
+#ifdef DEBUG
+ cout << "poll_ports no ports" << endl;
+#endif
usleep( no_ports_sleep * 1000 );
return false;
}
- int retval = poll( pfd, nfds, timeout );
+ int retval = ::poll( pfd, nfds, timeout );
if ( retval < 0 )
{
// gdb at work, perhaps
@@ -179,14 +210,21 @@ void MackieControlProtocol::handle_port_active( SurfacePort * port )
// finally update session state to the surface
// TODO but this is also done in set_active, and
// in fact update_surface won't execute unless
+#ifdef DEBUG
+ cout << "update_surface in handle_port_active" << endl;
+#endif
// _active == true
- //cout << "update_surface in handle_port_active" << endl;
update_surface();
}
void MackieControlProtocol::handle_port_init( Mackie::SurfacePort * sport )
{
- //cout << "MackieControlProtocol::handle_port_init" << endl;
+#ifdef DEBUG
+ cout << "MackieControlProtocol::handle_port_init" << endl;
+#endif
_ports_changed = true;
update_ports();
+#ifdef DEBUG
+ cout << "MackieControlProtocol::handle_port_init finish" << endl;
+#endif
}
diff --git a/libs/surfaces/mackie/mackie_jog_wheel.cc b/libs/surfaces/mackie/mackie_jog_wheel.cc
new file mode 100644
index 0000000000..d05eb23638
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_jog_wheel.cc
@@ -0,0 +1,194 @@
+#include <cmath>
+
+#include "mackie_jog_wheel.h"
+
+#include "mackie_control_protocol.h"
+#include "surface_port.h"
+#include "controls.h"
+#include "surface.h"
+
+#include <algorithm>
+
+using namespace Mackie;
+using std::isnan;
+
+JogWheel::JogWheel( MackieControlProtocol & mcp )
+: _mcp( mcp )
+, _transport_speed( 4.0 )
+, _transport_direction( 0 )
+, _shuttle_speed( 0.0 )
+{
+}
+
+JogWheel::State JogWheel::jog_wheel_state() const
+{
+ if ( !_jog_wheel_states.empty() )
+ return _jog_wheel_states.top();
+ else
+ return scroll;
+}
+
+void JogWheel::zoom_event( SurfacePort & port, Control & control, const ControlState & state )
+{
+}
+
+void JogWheel::scrub_event( SurfacePort & port, Control & control, const ControlState & state )
+{
+}
+
+void JogWheel::speed_event( SurfacePort & port, Control & control, const ControlState & state )
+{
+}
+
+void JogWheel::scroll_event( SurfacePort & port, Control & control, const ControlState & state )
+{
+}
+
+void JogWheel::jog_event( SurfacePort & port, Control & control, const ControlState & state )
+{
+ // TODO use current snap-to setting?
+ switch ( jog_wheel_state() )
+ {
+ case scroll:
+ _mcp.ScrollTimeline( state.delta * state.sign );
+ break;
+
+ case zoom:
+ // Chunky Zoom.
+ // TODO implement something similar to ScrollTimeline which
+ // ends up in Editor::control_scroll for smoother zooming.
+ if ( state.sign > 0 )
+ for ( unsigned int i = 0; i < state.ticks; ++i ) _mcp.ZoomIn();
+ else
+ for ( unsigned int i = 0; i < state.ticks; ++i ) _mcp.ZoomOut();
+ break;
+
+ case speed:
+ // locally, _transport_speed is an positive value
+ _transport_speed += _mcp.surface().scaled_delta( state, _mcp.get_session().transport_speed() );
+
+ // make sure no weirdness gets to the session
+ if ( _transport_speed < 0 || isnan( _transport_speed ) )
+ {
+ _transport_speed = 0.0;
+ }
+
+ // translate _transport_speed speed to a signed transport velocity
+ _mcp.get_session().request_transport_speed( transport_speed() * transport_direction() );
+ break;
+
+ case scrub:
+ {
+ if ( state.sign != 0 )
+ {
+ add_scrub_interval( _scrub_timer.restart() );
+ // x clicks per second => speed == 1.0
+ float speed = _mcp.surface().scrub_scaling_factor() / average_scrub_interval() * state.ticks;
+ _mcp.get_session().request_transport_speed( speed * state.sign );
+ }
+ else
+ {
+ // we have a stop event
+ check_scrubbing();
+ }
+ break;
+ }
+
+ case shuttle:
+ _shuttle_speed = _mcp.get_session().transport_speed();
+ _shuttle_speed += _mcp.surface().scaled_delta( state, _mcp.get_session().transport_speed() );
+ _mcp.get_session().request_transport_speed( _shuttle_speed );
+ break;
+
+ case select:
+ cout << "JogWheel select not implemented" << endl;
+ break;
+ }
+}
+
+void JogWheel::check_scrubbing()
+{
+ // if the last elapsed is greater than the average + std deviation, then stop
+ if ( !_scrub_intervals.empty() && _scrub_timer.elapsed() > average_scrub_interval() + std_dev_scrub_interval() )
+ {
+ _mcp.get_session().request_transport_speed( 0.0 );
+ _scrub_intervals.clear();
+ }
+}
+
+void JogWheel::push( State state )
+{
+ _jog_wheel_states.push( state );
+}
+
+void JogWheel::pop()
+{
+ if ( _jog_wheel_states.size() > 0 )
+ {
+ _jog_wheel_states.pop();
+ }
+}
+
+void JogWheel::zoom_state_toggle()
+{
+ if ( jog_wheel_state() == zoom )
+ pop();
+ else
+ push( zoom );
+}
+
+JogWheel::State JogWheel::scrub_state_cycle()
+{
+ State top = jog_wheel_state();
+ if ( top == scrub )
+ {
+ // stop scrubbing and go to shuttle
+ pop();
+ push( shuttle );
+ _shuttle_speed = 0.0;
+ }
+ else if ( top == shuttle )
+ {
+ // default to scroll, or the last selected
+ pop();
+ }
+ else
+ {
+ // start with scrub
+ push( scrub );
+ }
+
+ return jog_wheel_state();
+}
+
+void JogWheel::add_scrub_interval( unsigned long elapsed )
+{
+ if ( _scrub_intervals.size() > 5 )
+ {
+ _scrub_intervals.pop_front();
+ }
+ _scrub_intervals.push_back( elapsed );
+}
+
+float JogWheel::average_scrub_interval()
+{
+ float sum = 0.0;
+ for ( std::deque<unsigned long>::iterator it = _scrub_intervals.begin(); it != _scrub_intervals.end(); ++it )
+ {
+ sum += *it;
+ }
+ return sum / _scrub_intervals.size();
+}
+
+float JogWheel::std_dev_scrub_interval()
+{
+ float average = average_scrub_interval();
+
+ // calculate standard deviation
+ float sum = 0.0;
+ for ( std::deque<unsigned long>::iterator it = _scrub_intervals.begin(); it != _scrub_intervals.end(); ++it )
+ {
+ sum += pow( *it - average, 2 );
+ }
+ return sqrt( sum / _scrub_intervals.size() -1 );
+}
diff --git a/libs/surfaces/mackie/mackie_jog_wheel.h b/libs/surfaces/mackie/mackie_jog_wheel.h
new file mode 100644
index 0000000000..83a4364393
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_jog_wheel.h
@@ -0,0 +1,102 @@
+#ifndef mackie_jog_wheel
+#define mackie_jog_wheel
+
+#include "timer.h"
+
+#include <stack>
+#include <deque>
+#include <queue>
+
+class MackieControlProtocol;
+
+namespace Mackie
+{
+
+class SurfacePort;
+class Control;
+class ControlState;
+
+/**
+ A jog wheel can be used to control many things. This
+ handles all of the states and state transitions.
+
+ Mainly it exists to avoid putting a bunch of messy
+ stuff in MackieControlProtocol.
+
+ But it doesn't really know who it is, with stacks, queues and various
+ boolean state variables.
+*/
+class JogWheel
+{
+public:
+ enum State { scroll, zoom, speed, scrub, shuttle, select };
+
+ JogWheel( MackieControlProtocol & mcp );
+
+ /// As the wheel turns...
+ void jog_event( SurfacePort & port, Control & control, const ControlState & state );
+
+ // These are for incoming button presses that change the internal state
+ // but they're not actually used at the moment.
+ void zoom_event( SurfacePort & port, Control & control, const ControlState & state );
+ void scrub_event( SurfacePort & port, Control & control, const ControlState & state );
+ void speed_event( SurfacePort & port, Control & control, const ControlState & state );
+ void scroll_event( SurfacePort & port, Control & control, const ControlState & state );
+
+ /// Return the current jog wheel mode, which defaults to Scroll
+ State jog_wheel_state() const;
+
+ /// The current transport speed for ffwd and rew. Can be
+ /// set by wheel when they're pressed.
+ float transport_speed() const { return _transport_speed; }
+
+ /// one of -1,0,1
+ int transport_direction() const { return _transport_direction; }
+ void transport_direction( int rhs ) { _transport_direction = rhs; }
+
+ void push( State state );
+ void pop();
+
+ /// Turn zoom mode on and off
+ void zoom_state_toggle();
+
+ /**
+ Cycle scrub -> shuttle -> previous
+ */
+ State scrub_state_cycle();
+
+ /// Check to see when the last scrub event was
+ /// And stop scrubbing if it was too long ago.
+ /// Intended to be called from a periodic timer of
+ /// some kind.
+ void check_scrubbing();
+
+protected:
+ void add_scrub_interval( unsigned long elapsed );
+ float average_scrub_interval();
+ float std_dev_scrub_interval();
+
+private:
+ MackieControlProtocol & _mcp;
+
+ /// transport speed for ffwd and rew, controller by jog
+ float _transport_speed;
+ int _transport_direction;
+
+ /// Speed for shuttle
+ float _shuttle_speed;
+
+ /// a stack for keeping track of states
+ std::stack<State> _jog_wheel_states;
+
+ /// So we know how fast to set the transport speed while scrubbing
+ Timer _scrub_timer;
+
+ /// to keep track of what the current scrub rate is
+ /// so we can calculate a moving average
+ std::deque<unsigned long> _scrub_intervals;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_midi_builder.cc b/libs/surfaces/mackie/mackie_midi_builder.cc
index 8ed98a5720..89a6ce7789 100644
--- a/libs/surfaces/mackie/mackie_midi_builder.cc
+++ b/libs/surfaces/mackie/mackie_midi_builder.cc
@@ -20,9 +20,11 @@
#include <typeinfo>
#include <sstream>
#include <iomanip>
+#include <algorithm>
#include "controls.h"
#include "midi_byte_array.h"
+#include "mackie_port.h"
using namespace Mackie;
using namespace std;
@@ -44,12 +46,12 @@ MIDI::byte MackieMidiBuilder::calculate_pot_value( midi_pot_mode mode, const Con
return retval;
}
-MidiByteArray MackieMidiBuilder::build_led_ring( const Pot & pot, const ControlState & state )
+MidiByteArray MackieMidiBuilder::build_led_ring( const Pot & pot, const ControlState & state, midi_pot_mode mode )
{
- return build_led_ring( pot.led_ring(), state );
+ return build_led_ring( pot.led_ring(), state, mode );
}
-MidiByteArray MackieMidiBuilder::build_led_ring( const LedRing & led_ring, const ControlState & state )
+MidiByteArray MackieMidiBuilder::build_led_ring( const LedRing & led_ring, const ControlState & state, midi_pot_mode mode )
{
// The other way of doing this:
// 0x30 + pot/ring number (0-7)
@@ -58,9 +60,9 @@ MidiByteArray MackieMidiBuilder::build_led_ring( const LedRing & led_ring, const
// the control type
, midi_pot_id
// the id
- , 0x20 + led_ring.id()
+ , 0x20 + led_ring.raw_id()
// the value
- , calculate_pot_value( midi_pot_mode_dot, state )
+ , calculate_pot_value( mode, state )
);
}
@@ -82,7 +84,7 @@ MidiByteArray MackieMidiBuilder::build_led( const Led & led, LedState ls )
return MidiByteArray ( 3
, midi_button_id
- , led.id()
+ , led.raw_id()
, state
);
}
@@ -92,7 +94,7 @@ MidiByteArray MackieMidiBuilder::build_fader( const Fader & fader, float pos )
int posi = int( 0x3fff * pos );
return MidiByteArray ( 3
- , midi_fader_id | fader.id()
+ , midi_fader_id | fader.raw_id()
// lower-order bits
, posi & 0x7f
// higher-order bits
@@ -100,7 +102,7 @@ MidiByteArray MackieMidiBuilder::build_fader( const Fader & fader, float pos )
);
}
-MidiByteArray MackieMidiBuilder::zero_strip( const Strip & strip )
+MidiByteArray MackieMidiBuilder::zero_strip( SurfacePort & port, const Strip & strip )
{
Group::Controls::const_iterator it = strip.controls().begin();
MidiByteArray retval;
@@ -110,6 +112,10 @@ MidiByteArray MackieMidiBuilder::zero_strip( const Strip & strip )
if ( control.accepts_feedback() )
retval << zero_control( control );
}
+
+ // These must have sysex headers
+ retval << strip_display_blank( port, strip, 0 );
+ retval << strip_display_blank( port, strip, 1 );
return retval;
}
@@ -171,3 +177,98 @@ MidiByteArray MackieMidiBuilder::two_char_display( unsigned int value, const std
os << setfill('0') << setw(2) << value % 100;
return two_char_display( os.str() );
}
+
+MidiByteArray MackieMidiBuilder::strip_display_blank( SurfacePort & port, const Strip & strip, unsigned int line_number )
+{
+ // 6 spaces, not 7 because strip_display adds a space where appropriate
+ return strip_display( port, strip, line_number, " " );
+}
+
+MidiByteArray MackieMidiBuilder::strip_display( SurfacePort & port, const Strip & strip, unsigned int line_number, const std::string & line )
+{
+ if ( line_number > 1 )
+ {
+ throw runtime_error( "line_number must be 0 or 1" );
+ }
+
+ if ( strip.index() > 7 )
+ {
+ throw runtime_error( "strip.index() must be between 0 and 7" );
+ }
+
+#ifdef DEBUG
+ cout << "MackieMidiBuilder::strip_display index: " << strip.index() << ", line " << line_number << ": " << line << endl;
+#endif
+
+ MidiByteArray retval;
+
+ // sysex header
+ retval << port.sysex_hdr();
+
+ // code for display
+ retval << 0x12;
+ // offset (0 to 0x37 first line, 0x38 to 0x6f for second line )
+ retval << ( strip.index() * 7 + ( line_number * 0x38 ) );
+
+ // ascii data to display
+ retval << line;
+ // pad with " " out to 6 chars
+ for ( int i = line.length(); i < 6; ++i ) retval << ' ';
+
+ // column spacer, unless it's the right-hand column
+ if ( strip.index() < 7 ) retval << ' ';
+
+ // sysex trailer
+ retval << MIDI::eox;
+
+#ifdef DEBUG
+ cout << "MackieMidiBuilder::strip_display midi: " << retval << endl;
+#endif
+ return retval;
+}
+
+MidiByteArray MackieMidiBuilder::all_strips_display( SurfacePort & port, std::vector<std::string> & lines1, std::vector<std::string> & lines2 )
+{
+ MidiByteArray retval;
+ retval << 0x12 << 0;
+ // NOTE remember max 112 bytes per message, including sysex headers
+ retval << "Not working yet";
+ return retval;
+}
+
+MidiByteArray MackieMidiBuilder::timecode_display( SurfacePort & port, const std::string & timecode, const std::string & last_timecode )
+{
+ // if there's no change, send nothing, not even sysex header
+ if ( timecode == last_timecode ) return MidiByteArray();
+
+ // length sanity checking
+ string local_timecode = timecode;
+ // truncate to 10 characters
+ if ( local_timecode.length() > 10 ) local_timecode = local_timecode.substr( 0, 10 );
+ // pad to 10 characters
+ while ( local_timecode.length() < 10 ) local_timecode += " ";
+
+ // find the suffix of local_timecode that differs from last_timecode
+ std::pair<string::const_iterator,string::iterator> pp = mismatch( last_timecode.begin(), last_timecode.end(), local_timecode.begin() );
+
+ MidiByteArray retval;
+
+ // sysex header
+ retval << port.sysex_hdr();
+
+ // code for timecode display
+ retval << 0x10;
+
+ // translate characters. These are sent in reverse order of display
+ // hence the reverse iterators
+ string::reverse_iterator rend = reverse_iterator<string::iterator>( pp.second );
+ for ( string::reverse_iterator it = local_timecode.rbegin(); it != rend; ++it )
+ {
+ retval << translate_seven_segment( *it );
+ }
+
+ // sysex trailer
+ retval << MIDI::eox;
+
+ return retval;
+}
diff --git a/libs/surfaces/mackie/mackie_midi_builder.h b/libs/surfaces/mackie/mackie_midi_builder.h
index f0c3d51a54..b5fc9f73c9 100644
--- a/libs/surfaces/mackie/mackie_midi_builder.h
+++ b/libs/surfaces/mackie/mackie_midi_builder.h
@@ -20,10 +20,13 @@
#include "midi_byte_array.h"
#include "types.h"
+#include "controls.h"
namespace Mackie
{
+class SurfacePort;
+
/**
This knows how to build midi messages given a control and
a state.
@@ -37,9 +40,9 @@ public:
with the control id
*/
enum midi_types {
- midi_fader_id = 0xe0
- , midi_button_id = 0x90
- , midi_pot_id = 0xb0
+ midi_fader_id = Control::type_fader
+ , midi_button_id = Control::type_button
+ , midi_pot_id = Control::type_pot
};
/**
@@ -52,8 +55,8 @@ public:
, midi_pot_mode_spread = 3
};
- MidiByteArray build_led_ring( const Pot & pot, const ControlState & );
- MidiByteArray build_led_ring( const LedRing & led_ring, const ControlState & );
+ MidiByteArray build_led_ring( const Pot & pot, const ControlState &, midi_pot_mode mode = midi_pot_mode_dot );
+ MidiByteArray build_led_ring( const LedRing & led_ring, const ControlState &, midi_pot_mode mode = midi_pot_mode_dot );
MidiByteArray build_led( const Led & led, LedState ls );
MidiByteArray build_led( const Button & button, LedState ls );
@@ -61,7 +64,8 @@ public:
MidiByteArray build_fader( const Fader & fader, float pos );
/// return bytes that will reset all controls to their zero positions
- MidiByteArray zero_strip( const Strip & strip );
+ /// And blank the display for the strip. Pass SurfacePort so we know which sysex header to use.
+ MidiByteArray zero_strip( SurfacePort &, const Strip & strip );
// provide bytes to zero the given control
MidiByteArray zero_control( const Control & control );
@@ -72,6 +76,25 @@ public:
MidiByteArray two_char_display( const std::string & msg, const std::string & dots = " " );
MidiByteArray two_char_display( unsigned int value, const std::string & dots = " " );
+ /**
+ Timecode display. Only the difference between timecode and last_timecode will
+ be encoded, to save midi bandwidth. If they're the same, an empty array will
+ be returned
+ */
+ MidiByteArray timecode_display( SurfacePort &, const std::string & timecode, const std::string & last_timecode = "" );
+
+ /**
+ for displaying characters on the strip LCD
+ pass SurfacePort so we know which sysex header to use
+ */
+ MidiByteArray strip_display( SurfacePort &, const Strip & strip, unsigned int line_number, const std::string & line );
+
+ /// blank the strip LCD, ie write all spaces. Pass SurfacePort so we know which sysex header to use.
+ MidiByteArray strip_display_blank( SurfacePort &, const Strip & strip, unsigned int line_number );
+
+ /// for generating all strip names. Pass SurfacePort so we know which sysex header to use.
+ MidiByteArray all_strips_display( SurfacePort &, std::vector<std::string> & lines1, std::vector<std::string> & lines2 );
+
protected:
static MIDI::byte calculate_pot_value( midi_pot_mode mode, const ControlState & );
};
diff --git a/libs/surfaces/mackie/mackie_port.cc b/libs/surfaces/mackie/mackie_port.cc
index 75e78e7f15..d767c4c745 100644
--- a/libs/surfaces/mackie/mackie_port.cc
+++ b/libs/surfaces/mackie/mackie_port.cc
@@ -23,6 +23,8 @@
#include "controls.h"
#include "surface.h"
+#include <glibmm/main.h>
+
#include <midi++/types.h>
#include <midi++/port.h>
#include <sigc++/sigc++.h>
@@ -49,14 +51,20 @@ MackiePort::MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int numb
, _emulation( none )
, _initialising( true )
{
- //cout << "MackiePort::MackiePort" <<endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::MackiePort" <<endl;
+#endif
}
MackiePort::~MackiePort()
{
- //cout << "~MackiePort" << endl;
+#ifdef PORT_DEBUG
+ cout << "~MackiePort" << endl;
+#endif
close();
- //cout << "~MackiePort finished" << endl;
+#ifdef PORT_DEBUG
+ cout << "~MackiePort finished" << endl;
+#endif
}
int MackiePort::strips() const
@@ -83,7 +91,9 @@ int MackiePort::strips() const
// should really be in MackiePort
void MackiePort::open()
{
- //cout << "MackiePort::open " << *this << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::open " << *this << endl;
+#endif
_sysex = port().input()->sysex.connect( ( mem_fun (*this, &MackiePort::handle_midi_sysex) ) );
// make sure the device is connected
@@ -92,14 +102,18 @@ void MackiePort::open()
void MackiePort::close()
{
- //cout << "MackiePort::close" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::close" << endl;
+#endif
// disconnect signals
_any.disconnect();
_sysex.disconnect();
// TODO emit a "closing" signal?
- //cout << "MackiePort::close finished" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::close finished" << endl;
+#endif
}
const MidiByteArray & MackiePort::sysex_hdr() const
@@ -113,57 +127,6 @@ const MidiByteArray & MackiePort::sysex_hdr() const
return mackie_sysex_hdr;
}
-Control & MackiePort::lookup_control( const MidiByteArray & bytes )
-{
- Control * control = 0;
- int midi_id = -1;
- MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
- switch( midi_type )
- {
- // fader
- case MackieMidiBuilder::midi_fader_id:
- midi_id = bytes[0] & 0x0f;
- control = _mcp.surface().faders[midi_id];
- if ( control == 0 )
- {
- ostringstream os;
- os << "control for fader" << midi_id << " is null";
- throw MackieControlException( os.str() );
- }
- break;
-
- // button
- case MackieMidiBuilder::midi_button_id:
- midi_id = bytes[1];
- control = _mcp.surface().buttons[midi_id];
- if ( control == 0 )
- {
- ostringstream os;
- os << "control for button" << midi_id << " is null";
- throw MackieControlException( os.str() );
- }
- break;
-
- // pot (jog wheel, external control)
- case MackieMidiBuilder::midi_pot_id:
- midi_id = bytes[1] & 0x1f;
- control = _mcp.surface().pots[midi_id];
- if ( control == 0 )
- {
- ostringstream os;
- os << "control for button" << midi_id << " is null";
- throw MackieControlException( os.str() );
- }
- break;
-
- default:
- ostringstream os;
- os << "Cannot find control for " << bytes;
- throw MackieControlException( os.str() );
- }
- return *control;
-}
-
MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiByteArray::iterator end )
{
MidiByteArray l;
@@ -186,7 +149,9 @@ MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiB
MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes )
{
// handle host connection query
- //cout << "host connection query: " << bytes << endl;
+#ifdef PORT_DEBUG
+ cout << "host connection query: " << bytes << endl;
+#endif
if ( bytes.size() != 18 )
{
@@ -207,7 +172,9 @@ MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes )
// not used right now
MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes )
{
- //cout << "host_connection_confirmation: " << bytes << endl;
+#ifdef PORT_DEBUG
+ cout << "host_connection_confirmation: " << bytes << endl;
+#endif
// decode host connection confirmation
if ( bytes.size() != 14 )
@@ -224,17 +191,20 @@ MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & by
void MackiePort::probe_emulation( const MidiByteArray & bytes )
{
- //cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
- string version_string;
- for ( int i = 6; i < 11; ++i ) version_string.append( 1, (char)bytes[i] );
- //cout << "version_string: " << version_string << endl;
+#if 0
+ cout << "MackiePort::probe_emulation: " << bytes.size() << ", " << bytes << endl;
+
+ MidiByteArray version_string;
+ for ( int i = 6; i < 11; ++i ) version_string << bytes[i];
+ cout << "version_string: " << version_string << endl;
+#endif
// TODO investigate using serial number. Also, possibly size of bytes might
// give an indication. Also, apparently MCU sends non-documented messages
// sometimes.
if (!_initialising)
{
- cout << "MackiePort::probe_emulation out of sequence." << endl;
+ //cout << "MackiePort::probe_emulation out of sequence." << endl;
return;
}
@@ -243,11 +213,15 @@ void MackiePort::probe_emulation( const MidiByteArray & bytes )
void MackiePort::init()
{
- //cout << "MackiePort::init" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::init" << endl;
+#endif
init_mutex.lock();
_initialising = true;
- //cout << "MackiePort::lock acquired" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::init lock acquired" << endl;
+#endif
// emit pre-init signal
init_event();
@@ -263,13 +237,19 @@ void MackiePort::init()
void MackiePort::finalise_init( bool yn )
{
- //cout << "MackiePort::finalise_init" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::finalise_init" << endl;
+#endif
bool emulation_ok = false;
// probing doesn't work very well, so just use a config variable
// to set the emulation mode
+ // TODO This might have to be specified on a per-port basis
+ // in the config file
+ // if an mcu and a bcf are needed to work as one surface
if ( _emulation == none )
{
+ // TODO same as code in mackie_control_protocol.cc
if ( ARDOUR::Config->get_mackie_emulation() == "bcf" )
{
_emulation = bcf2000;
@@ -296,11 +276,39 @@ void MackiePort::finalise_init( bool yn )
active_event();
// start handling messages from controls
- _any = port().input()->any.connect( ( mem_fun (*this, &MackiePort::handle_midi_any) ) );
+ connect_any();
}
_initialising = false;
init_cond.signal();
init_mutex.unlock();
+#ifdef PORT_DEBUG
+ cout << "MackiePort::finalise_init lock released" << endl;
+#endif
+}
+
+void MackiePort::connect_any()
+{
+/*
+ Doesn't work because there isn't an == operator for slots
+ MIDI::Signal::slot_list_type slots = port().input()->any.slots();
+
+ if ( find( slots.begin(), slots.end(), mem_fun( *this, &MackiePort::handle_midi_any ) ) == slots.end() )
+*/
+ // TODO but this will break if midi tracing is turned on
+ if ( port().input()->any.empty() )
+ {
+#ifdef DEBUG
+ cout << "connect input parser " << port().input() << " to handle_midi_any" << endl;
+#endif
+ _any = port().input()->any.connect( mem_fun( *this, &MackiePort::handle_midi_any ) );
+#ifdef DEBUG
+ cout << "input parser any connections: " << port().input()->any.size() << endl;
+#endif
+ }
+ else
+ {
+ cout << "MackiePort::connect_any already connected" << endl;
+ }
}
bool MackiePort::wait_for_init()
@@ -308,18 +316,26 @@ bool MackiePort::wait_for_init()
Glib::Mutex::Lock lock( init_mutex );
while ( _initialising )
{
- //cout << "MackiePort::wait_for_active waiting" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::wait_for_active waiting" << endl;
+#endif
init_cond.wait( init_mutex );
- //cout << "MackiePort::wait_for_active released" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::wait_for_active released" << endl;
+#endif
}
- //cout << "MackiePort::wait_for_active returning" << endl;
+#ifdef PORT_DEBUG
+ cout << "MackiePort::wait_for_active returning" << endl;
+#endif
return SurfacePort::active();
}
void MackiePort::handle_midi_sysex (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
{
MidiByteArray bytes( count, raw_bytes );
- //cout << "handle_midi_sysex: " << bytes << endl;
+#ifdef PORT_DEBUG
+ cout << "handle_midi_sysex: " << bytes << endl;
+#endif
switch( bytes[5] )
{
case 0x01:
@@ -342,16 +358,99 @@ void MackiePort::handle_midi_sysex (MIDI::Parser & parser, MIDI::byte * raw_byte
}
}
+Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count )
+{
+ // Don't instantiate a MidiByteArray here unless it's needed for exceptions.
+ // Reason being that this method is called for every single incoming
+ // midi event, and it needs to be as efficient as possible.
+ Control * control = 0;
+ MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000
+ switch( midi_type )
+ {
+ // fader
+ case MackieMidiBuilder::midi_fader_id:
+ {
+ int midi_id = bytes[0] & 0x0f;
+ control = _mcp.surface().faders[midi_id];
+ if ( control == 0 )
+ {
+ MidiByteArray mba( count, bytes );
+ ostringstream os;
+ os << "control for fader" << bytes << " id " << midi_id << " is null";
+ throw MackieControlException( os.str() );
+ }
+ break;
+ }
+
+ // button
+ case MackieMidiBuilder::midi_button_id:
+ control = _mcp.surface().buttons[bytes[1]];
+ if ( control == 0 )
+ {
+ MidiByteArray mba( count, bytes );
+ ostringstream os;
+ os << "control for button " << bytes << " is null";
+ throw MackieControlException( os.str() );
+ }
+ break;
+
+ // pot (jog wheel, external control)
+ case MackieMidiBuilder::midi_pot_id:
+ control = _mcp.surface().pots[bytes[1]];
+ if ( control == 0 )
+ {
+ MidiByteArray mba( count, bytes );
+ ostringstream os;
+ os << "control for rotary " << mba << " is null";
+ throw MackieControlException( os.str() );
+ }
+ break;
+
+ default:
+ MidiByteArray mba( count, bytes );
+ ostringstream os;
+ os << "Cannot find control for " << bytes;
+ throw MackieControlException( os.str() );
+ }
+ return *control;
+}
+
+bool MackiePort::handle_control_timeout_event ( Control * control )
+{
+ // empty control_state
+ ControlState control_state;
+ control->in_use( false );
+ control_event( *this, *control, control_state );
+
+ // only call this method once from the timer
+ return false;
+}
+
// converts midi messages into control_event signals
+// it might be worth combining this with lookup_control
+// because they have similar logic flows.
void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
{
+#ifdef DEBUG
MidiByteArray bytes( count, raw_bytes );
+ cout << "MackiePort::handle_midi_any " << bytes << endl;
+#endif
try
{
// ignore sysex messages
- if ( bytes[0] == MIDI::sysex ) return;
+ if ( raw_bytes[0] == MIDI::sysex ) return;
- Control & control = lookup_control( bytes );
+ // sanity checking
+ if ( count != 3 )
+ {
+ ostringstream os;
+ MidiByteArray mba( count, raw_bytes );
+ os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba;
+ throw MackieControlException( os.str() );
+ }
+
+ Control & control = lookup_control( raw_bytes, count );
+ control.in_use( true );
// This handles incoming bytes. Outgoing bytes
// are sent by the signal handlers.
@@ -359,41 +458,74 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
{
// fader
case Control::type_fader:
- {
- // for a BCF2000, max is 7f for high-order byte and 0x70 for low-order byte
- // According to the Logic docs, these should both be 0x7f.
- // Although it does mention something about only the top-order
- // 10 bits out of 14 being used
- int midi_pos = ( bytes[2] << 7 ) + bytes[1];
- control_event( *this, control, float(midi_pos) / float(0x3fff) );
- }
- break;
+ {
+ // only the top-order 10 bits out of 14 are used
+ int midi_pos = ( ( raw_bytes[2] << 7 ) + raw_bytes[1] ) >> 4;
+
+ // in_use is set by the MackieControlProtocol::handle_strip_button
+
+ // relies on implicit ControlState constructor
+ control_event( *this, control, float(midi_pos) / float(0x3ff) );
+ }
+ break;
// button
case Control::type_button:
- control_event( *this, control, bytes[2] == 0x7f ? press : release );
+ {
+ ControlState control_state( raw_bytes[2] == 0x7f ? press : release );
+ control.in_use( control_state.button_state == press );
+ control_event( *this, control, control_state );
+
break;
+ }
// pot (jog wheel, external control)
case Control::type_pot:
- {
- ControlState state;
-
- // bytes[2] & 0b01000000 (0x40) give sign
- int sign = ( bytes[2] & 0x40 ) == 0 ? 1 : -1;
- // bytes[2] & 0b00111111 (0x3f) gives delta
- state.ticks = ( bytes[2] & 0x3f) * sign;
- state.delta = float( state.ticks ) / float( 0x3f );
-
- control_event( *this, control, state );
- }
+ {
+ ControlState state;
+
+ // bytes[2] & 0b01000000 (0x40) give sign
+ state.sign = ( raw_bytes[2] & 0x40 ) == 0 ? 1 : -1;
+ // bytes[2] & 0b00111111 (0x3f) gives delta
+ state.ticks = ( raw_bytes[2] & 0x3f);
+ state.delta = float( state.ticks ) / float( 0x3f );
+
+ /*
+ Pots only emit events when they move, not when they
+ stop moving. So to get a stop event, we need to use a timeout.
+ */
+ // this is set to false ...
+ control.in_use( true );
+
+ // ... by this timeout
+
+ // first disconnect any previous timeouts
+ control.in_use_connection.disconnect();
+
+ // now connect a new timeout to call handle_control_timeout_event
+ sigc::slot<bool> timeout_slot = sigc::bind(
+ mem_fun( *this, &MackiePort::handle_control_timeout_event )
+ , &control
+ );
+ control.in_use_connection = Glib::signal_timeout().connect(
+ timeout_slot
+ , control.in_use_timeout()
+ );
+
+ // emit the control event
+ control_event( *this, control, state );
break;
+ }
default:
cerr << "Do not understand control type " << control;
}
}
catch( MackieControlException & e )
{
- //cout << bytes << ' ' << e.what() << endl;
+ MidiByteArray bytes( count, raw_bytes );
+ cout << bytes << ' ' << e.what() << endl;
}
+#ifdef DEBUG
+ cout << "finished MackiePort::handle_midi_any " << bytes << endl;
+#endif
}
diff --git a/libs/surfaces/mackie/mackie_port.h b/libs/surfaces/mackie/mackie_port.h
index 2ad5cf6154..26ec1ca799 100644
--- a/libs/surfaces/mackie/mackie_port.h
+++ b/libs/surfaces/mackie/mackie_port.h
@@ -55,12 +55,12 @@ public:
virtual const MidiByteArray & sysex_hdr() const;
/// Handle device initialisation
- void handle_midi_sysex( MIDI::Parser &, MIDI::byte *, size_t );
+ void handle_midi_sysex( MIDI::Parser &, MIDI::byte *, size_t count );
/// Handle all control messags
- void handle_midi_any( MIDI::Parser &, MIDI::byte *, size_t );
+ void handle_midi_any( MIDI::Parser &, MIDI::byte *, size_t count );
- Control & lookup_control( const MidiByteArray & bytes );
+ Control & lookup_control( MIDI::byte *, size_t count );
/// return the number of strips associated with this port
virtual int strips() const;
@@ -71,6 +71,10 @@ public:
emulation_t emulation() const { return _emulation; }
+ /// Connect the any signal from the parser to handle_midi_any
+ /// unless it's already connected
+ void connect_any();
+
protected:
/**
The initialisation sequence is fairly complex. First a lock is acquired
@@ -105,6 +109,10 @@ protected:
*/
void probe_emulation( const MidiByteArray & bytes );
+ /// Handle timeout events set for controls that don't emit
+ /// an off event
+ bool handle_control_timeout_event ( Control * );
+
private:
MackieControlProtocol & _mcp;
port_type_t _port_type;
diff --git a/libs/surfaces/mackie/mackie_surface.cc b/libs/surfaces/mackie/mackie_surface.cc
index b527f710cc..dbba726062 100644
--- a/libs/surfaces/mackie/mackie_surface.cc
+++ b/libs/surfaces/mackie/mackie_surface.cc
@@ -1,1504 +1,18 @@
-/*
- Generated by scripts/generate-surface.rb
-*/
-
#include "mackie_surface.h"
+#include "surface_port.h"
+#include "mackie_midi_builder.h"
-#include "controls.h"
-#include "mackie_button_handler.h"
+#include <cmath>
+#include <string>
using namespace Mackie;
-void Mackie::MackieSurface::init_controls()
+void MackieSurface::display_timecode( SurfacePort & port, MackieMidiBuilder & builder, const std::string & timecode, const std::string & timecode_last )
{
- // intialise groups and strips
- Group * group = 0;
-
- // make sure there are enough strips
- strips.resize( 8 );
-
- group = new Group ( "user" );
- groups["user"] = group;
-
- group = new Group ( "assignment" );
- groups["assignment"] = group;
-
- group = new Group ( "none" );
- groups["none"] = group;
-
- group = new MasterStrip ( "master", 0 );
- groups["master"] = group;
- strips[0] = dynamic_cast<Strip*>( group );
-
- group = new Strip ( "strip_1", 0 );
- groups["strip_1"] = group;
- strips[0] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "cursor" );
- groups["cursor"] = group;
-
- group = new Strip ( "strip_2", 1 );
- groups["strip_2"] = group;
- strips[1] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "functions" );
- groups["functions"] = group;
-
- group = new Group ( "automation" );
- groups["automation"] = group;
-
- group = new Strip ( "strip_3", 2 );
- groups["strip_3"] = group;
- strips[2] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "display" );
- groups["display"] = group;
-
- group = new Strip ( "strip_4", 3 );
- groups["strip_4"] = group;
- strips[3] = dynamic_cast<Strip*>( group );
-
- group = new Strip ( "strip_5", 4 );
- groups["strip_5"] = group;
- strips[4] = dynamic_cast<Strip*>( group );
-
- group = new Strip ( "strip_6", 5 );
- groups["strip_6"] = group;
- strips[5] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "transport" );
- groups["transport"] = group;
-
- group = new Strip ( "strip_7", 6 );
- groups["strip_7"] = group;
- strips[6] = dynamic_cast<Strip*>( group );
-
- group = new Group ( "modifiers" );
- groups["modifiers"] = group;
-
- group = new Group ( "bank" );
- groups["bank"] = group;
-
- group = new Strip ( "strip_8", 7 );
- groups["strip_8"] = group;
- strips[7] = dynamic_cast<Strip*>( group );
-
-
- // initialise controls
- Control * control = 0;
-
- group = groups["strip_1"];
- control = new Fader ( 0, 1, "gain", *group );
- faders[0x00] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Fader ( 1, 2, "gain", *group );
- faders[0x01] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Fader ( 2, 3, "gain", *group );
- faders[0x02] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Fader ( 3, 4, "gain", *group );
- faders[0x03] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Fader ( 4, 5, "gain", *group );
- faders[0x04] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Fader ( 5, 6, "gain", *group );
- faders[0x05] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Fader ( 6, 7, "gain", *group );
- faders[0x06] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Fader ( 7, 8, "gain", *group );
- faders[0x07] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["master"];
- control = new Fader ( 8, 1, "gain", *group );
- faders[0x08] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Pot ( 16, 1, "vpot", *group );
- pots[0x10] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Pot ( 17, 2, "vpot", *group );
- pots[0x11] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Pot ( 18, 3, "vpot", *group );
- pots[0x12] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Pot ( 19, 4, "vpot", *group );
- pots[0x13] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Pot ( 20, 5, "vpot", *group );
- pots[0x14] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Pot ( 21, 6, "vpot", *group );
- pots[0x15] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Pot ( 22, 7, "vpot", *group );
- pots[0x16] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Pot ( 23, 8, "vpot", *group );
- pots[0x17] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["none"];
- control = new Pot ( 60, 1, "jog", *group );
- pots[0x3c] = control;
- controls.push_back( control );
- controls_by_name["jog"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Pot ( 46, 1, "external", *group );
- pots[0x2e] = control;
- controls.push_back( control );
- controls_by_name["external"] = control;
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 0, 1, "recenable", *group );
- buttons[0x00] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 1, 2, "recenable", *group );
- buttons[0x01] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 2, 3, "recenable", *group );
- buttons[0x02] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 3, 4, "recenable", *group );
- buttons[0x03] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 4, 5, "recenable", *group );
- buttons[0x04] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 5, 6, "recenable", *group );
- buttons[0x05] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 6, 7, "recenable", *group );
- buttons[0x06] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Button ( 7, 8, "recenable", *group );
- buttons[0x07] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 8, 1, "solo", *group );
- buttons[0x08] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 9, 2, "solo", *group );
- buttons[0x09] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 10, 3, "solo", *group );
- buttons[0x0a] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 11, 4, "solo", *group );
- buttons[0x0b] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 12, 5, "solo", *group );
- buttons[0x0c] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 13, 6, "solo", *group );
- buttons[0x0d] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 14, 7, "solo", *group );
- buttons[0x0e] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Button ( 15, 8, "solo", *group );
- buttons[0x0f] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 16, 1, "mute", *group );
- buttons[0x10] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 17, 2, "mute", *group );
- buttons[0x11] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 18, 3, "mute", *group );
- buttons[0x12] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 19, 4, "mute", *group );
- buttons[0x13] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 20, 5, "mute", *group );
- buttons[0x14] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 21, 6, "mute", *group );
- buttons[0x15] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 22, 7, "mute", *group );
- buttons[0x16] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Button ( 23, 8, "mute", *group );
- buttons[0x17] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 24, 1, "select", *group );
- buttons[0x18] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 25, 2, "select", *group );
- buttons[0x19] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 26, 3, "select", *group );
- buttons[0x1a] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 27, 4, "select", *group );
- buttons[0x1b] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 28, 5, "select", *group );
- buttons[0x1c] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 29, 6, "select", *group );
- buttons[0x1d] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 30, 7, "select", *group );
- buttons[0x1e] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Button ( 31, 8, "select", *group );
- buttons[0x1f] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 32, 1, "vselect", *group );
- buttons[0x20] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 33, 2, "vselect", *group );
- buttons[0x21] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 34, 3, "vselect", *group );
- buttons[0x22] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 35, 4, "vselect", *group );
- buttons[0x23] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 36, 5, "vselect", *group );
- buttons[0x24] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 37, 6, "vselect", *group );
- buttons[0x25] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 38, 7, "vselect", *group );
- buttons[0x26] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Button ( 39, 8, "vselect", *group );
- buttons[0x27] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 40, 1, "io", *group );
- buttons[0x28] = control;
- controls.push_back( control );
- controls_by_name["io"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 41, 1, "sends", *group );
- buttons[0x29] = control;
- controls.push_back( control );
- controls_by_name["sends"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 42, 1, "pan", *group );
- buttons[0x2a] = control;
- controls.push_back( control );
- controls_by_name["pan"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 43, 1, "plugin", *group );
- buttons[0x2b] = control;
- controls.push_back( control );
- controls_by_name["plugin"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 44, 1, "eq", *group );
- buttons[0x2c] = control;
- controls.push_back( control );
- controls_by_name["eq"] = control;
- group->add( *control );
-
- group = groups["assignment"];
- control = new Button ( 45, 1, "dyn", *group );
- buttons[0x2d] = control;
- controls.push_back( control );
- controls_by_name["dyn"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 46, 1, "left", *group );
- buttons[0x2e] = control;
- controls.push_back( control );
- controls_by_name["left"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 47, 1, "right", *group );
- buttons[0x2f] = control;
- controls.push_back( control );
- controls_by_name["right"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 48, 1, "channel_left", *group );
- buttons[0x30] = control;
- controls.push_back( control );
- controls_by_name["channel_left"] = control;
- group->add( *control );
-
- group = groups["bank"];
- control = new Button ( 49, 1, "channel_right", *group );
- buttons[0x31] = control;
- controls.push_back( control );
- controls_by_name["channel_right"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 50, 1, "flip", *group );
- buttons[0x32] = control;
- controls.push_back( control );
- controls_by_name["flip"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 51, 1, "edit", *group );
- buttons[0x33] = control;
- controls.push_back( control );
- controls_by_name["edit"] = control;
- group->add( *control );
-
- group = groups["display"];
- control = new Button ( 52, 1, "name_value", *group );
- buttons[0x34] = control;
- controls.push_back( control );
- controls_by_name["name_value"] = control;
- group->add( *control );
-
- group = groups["display"];
- control = new Button ( 53, 1, "smpte_beats", *group );
- buttons[0x35] = control;
- controls.push_back( control );
- controls_by_name["smpte_beats"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 54, 1, "F1", *group );
- buttons[0x36] = control;
- controls.push_back( control );
- controls_by_name["F1"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 55, 1, "F2", *group );
- buttons[0x37] = control;
- controls.push_back( control );
- controls_by_name["F2"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 56, 1, "F3", *group );
- buttons[0x38] = control;
- controls.push_back( control );
- controls_by_name["F3"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 57, 1, "F4", *group );
- buttons[0x39] = control;
- controls.push_back( control );
- controls_by_name["F4"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 58, 1, "F5", *group );
- buttons[0x3a] = control;
- controls.push_back( control );
- controls_by_name["F5"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 59, 1, "F6", *group );
- buttons[0x3b] = control;
- controls.push_back( control );
- controls_by_name["F6"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 60, 1, "F7", *group );
- buttons[0x3c] = control;
- controls.push_back( control );
- controls_by_name["F7"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 61, 1, "F8", *group );
- buttons[0x3d] = control;
- controls.push_back( control );
- controls_by_name["F8"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 62, 1, "F9", *group );
- buttons[0x3e] = control;
- controls.push_back( control );
- controls_by_name["F9"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 63, 1, "F10", *group );
- buttons[0x3f] = control;
- controls.push_back( control );
- controls_by_name["F10"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 64, 1, "F11", *group );
- buttons[0x40] = control;
- controls.push_back( control );
- controls_by_name["F11"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 65, 1, "F12", *group );
- buttons[0x41] = control;
- controls.push_back( control );
- controls_by_name["F12"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 66, 1, "F13", *group );
- buttons[0x42] = control;
- controls.push_back( control );
- controls_by_name["F13"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 67, 1, "F14", *group );
- buttons[0x43] = control;
- controls.push_back( control );
- controls_by_name["F14"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 68, 1, "F15", *group );
- buttons[0x44] = control;
- controls.push_back( control );
- controls_by_name["F15"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 69, 1, "F16", *group );
- buttons[0x45] = control;
- controls.push_back( control );
- controls_by_name["F16"] = control;
- group->add( *control );
-
- group = groups["modifiers"];
- control = new Button ( 70, 1, "shift", *group );
- buttons[0x46] = control;
- controls.push_back( control );
- controls_by_name["shift"] = control;
- group->add( *control );
-
- group = groups["modifiers"];
- control = new Button ( 71, 1, "option", *group );
- buttons[0x47] = control;
- controls.push_back( control );
- controls_by_name["option"] = control;
- group->add( *control );
-
- group = groups["modifiers"];
- control = new Button ( 72, 1, "control", *group );
- buttons[0x48] = control;
- controls.push_back( control );
- controls_by_name["control"] = control;
- group->add( *control );
-
- group = groups["modifiers"];
- control = new Button ( 73, 1, "cmd_alt", *group );
- buttons[0x49] = control;
- controls.push_back( control );
- controls_by_name["cmd_alt"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 74, 1, "on", *group );
- buttons[0x4a] = control;
- controls.push_back( control );
- controls_by_name["on"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 75, 1, "rec_ready", *group );
- buttons[0x4b] = control;
- controls.push_back( control );
- controls_by_name["rec_ready"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 76, 1, "undo", *group );
- buttons[0x4c] = control;
- controls.push_back( control );
- controls_by_name["undo"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 77, 1, "snapshot", *group );
- buttons[0x4d] = control;
- controls.push_back( control );
- controls_by_name["snapshot"] = control;
- group->add( *control );
-
- group = groups["automation"];
- control = new Button ( 78, 1, "touch", *group );
- buttons[0x4e] = control;
- controls.push_back( control );
- controls_by_name["touch"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 79, 1, "redo", *group );
- buttons[0x4f] = control;
- controls.push_back( control );
- controls_by_name["redo"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 80, 1, "marker", *group );
- buttons[0x50] = control;
- controls.push_back( control );
- controls_by_name["marker"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 81, 1, "enter", *group );
- buttons[0x51] = control;
- controls.push_back( control );
- controls_by_name["enter"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 82, 1, "cancel", *group );
- buttons[0x52] = control;
- controls.push_back( control );
- controls_by_name["cancel"] = control;
- group->add( *control );
-
- group = groups["functions"];
- control = new Button ( 83, 1, "mixer", *group );
- buttons[0x53] = control;
- controls.push_back( control );
- controls_by_name["mixer"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 84, 1, "frm_left", *group );
- buttons[0x54] = control;
- controls.push_back( control );
- controls_by_name["frm_left"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 85, 1, "frm_right", *group );
- buttons[0x55] = control;
- controls.push_back( control );
- controls_by_name["frm_right"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 86, 1, "loop", *group );
- buttons[0x56] = control;
- controls.push_back( control );
- controls_by_name["loop"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 87, 1, "punch_in", *group );
- buttons[0x57] = control;
- controls.push_back( control );
- controls_by_name["punch_in"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 88, 1, "punch_out", *group );
- buttons[0x58] = control;
- controls.push_back( control );
- controls_by_name["punch_out"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 89, 1, "home", *group );
- buttons[0x59] = control;
- controls.push_back( control );
- controls_by_name["home"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 90, 1, "end", *group );
- buttons[0x5a] = control;
- controls.push_back( control );
- controls_by_name["end"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 91, 1, "rewind", *group );
- buttons[0x5b] = control;
- controls.push_back( control );
- controls_by_name["rewind"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 92, 1, "ffwd", *group );
- buttons[0x5c] = control;
- controls.push_back( control );
- controls_by_name["ffwd"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 93, 1, "stop", *group );
- buttons[0x5d] = control;
- controls.push_back( control );
- controls_by_name["stop"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 94, 1, "play", *group );
- buttons[0x5e] = control;
- controls.push_back( control );
- controls_by_name["play"] = control;
- group->add( *control );
-
- group = groups["transport"];
- control = new Button ( 95, 1, "record", *group );
- buttons[0x5f] = control;
- controls.push_back( control );
- controls_by_name["record"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 96, 1, "cursor_up", *group );
- buttons[0x60] = control;
- controls.push_back( control );
- controls_by_name["cursor_up"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 97, 1, "cursor_down", *group );
- buttons[0x61] = control;
- controls.push_back( control );
- controls_by_name["cursor_down"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 98, 1, "cursor_left", *group );
- buttons[0x62] = control;
- controls.push_back( control );
- controls_by_name["cursor_left"] = control;
- group->add( *control );
-
- group = groups["cursor"];
- control = new Button ( 99, 1, "cursor_right", *group );
- buttons[0x63] = control;
- controls.push_back( control );
- controls_by_name["cursor_right"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 100, 1, "zoom", *group );
- buttons[0x64] = control;
- controls.push_back( control );
- controls_by_name["zoom"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Button ( 101, 1, "scrub", *group );
- buttons[0x65] = control;
- controls.push_back( control );
- controls_by_name["scrub"] = control;
- group->add( *control );
-
- group = groups["user"];
- control = new Button ( 102, 1, "user_a", *group );
- buttons[0x66] = control;
- controls.push_back( control );
- controls_by_name["user_a"] = control;
- group->add( *control );
-
- group = groups["user"];
- control = new Button ( 103, 1, "user_b", *group );
- buttons[0x67] = control;
- controls.push_back( control );
- controls_by_name["user_b"] = control;
- group->add( *control );
-
- group = groups["strip_1"];
- control = new Button ( 104, 1, "fader_touch", *group );
- buttons[0x68] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_2"];
- control = new Button ( 105, 2, "fader_touch", *group );
- buttons[0x69] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_3"];
- control = new Button ( 106, 3, "fader_touch", *group );
- buttons[0x6a] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_4"];
- control = new Button ( 107, 4, "fader_touch", *group );
- buttons[0x6b] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_5"];
- control = new Button ( 108, 5, "fader_touch", *group );
- buttons[0x6c] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_6"];
- control = new Button ( 109, 6, "fader_touch", *group );
- buttons[0x6d] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_7"];
- control = new Button ( 110, 7, "fader_touch", *group );
- buttons[0x6e] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["strip_8"];
- control = new Button ( 111, 8, "fader_touch", *group );
- buttons[0x6f] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["master"];
- control = new Button ( 112, 1, "fader_touch", *group );
- buttons[0x70] = control;
- controls.push_back( control );
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 113, 1, "smpte", *group );
- leds[0x71] = control;
- controls.push_back( control );
- controls_by_name["smpte"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 114, 1, "beats", *group );
- leds[0x72] = control;
- controls.push_back( control );
- controls_by_name["beats"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 115, 1, "solo", *group );
- leds[0x73] = control;
- controls.push_back( control );
- controls_by_name["solo"] = control;
- group->add( *control );
-
- group = groups["none"];
- control = new Led ( 118, 1, "relay_click", *group );
- leds[0x76] = control;
- controls.push_back( control );
- controls_by_name["relay_click"] = control;
- group->add( *control );
-
+ port.write( builder.timecode_display( port, timecode, timecode_last ) );
}
-void Mackie::MackieSurface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
+float MackieSurface::scaled_delta( const ControlState & state, float current_speed )
{
- if ( bs != press && bs != release )
- {
- mbh.update_led( button, none );
- return;
- }
-
- LedState ls;
- switch ( button.id() )
- {
-
- case 0x28: // io
- switch ( bs ) {
- case press: ls = mbh.io_press( button ); break;
- case release: ls = mbh.io_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x29: // sends
- switch ( bs ) {
- case press: ls = mbh.sends_press( button ); break;
- case release: ls = mbh.sends_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2a: // pan
- switch ( bs ) {
- case press: ls = mbh.pan_press( button ); break;
- case release: ls = mbh.pan_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2b: // plugin
- switch ( bs ) {
- case press: ls = mbh.plugin_press( button ); break;
- case release: ls = mbh.plugin_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2c: // eq
- switch ( bs ) {
- case press: ls = mbh.eq_press( button ); break;
- case release: ls = mbh.eq_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2d: // dyn
- switch ( bs ) {
- case press: ls = mbh.dyn_press( button ); break;
- case release: ls = mbh.dyn_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2e: // left
- switch ( bs ) {
- case press: ls = mbh.left_press( button ); break;
- case release: ls = mbh.left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x2f: // right
- switch ( bs ) {
- case press: ls = mbh.right_press( button ); break;
- case release: ls = mbh.right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x30: // channel_left
- switch ( bs ) {
- case press: ls = mbh.channel_left_press( button ); break;
- case release: ls = mbh.channel_left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x31: // channel_right
- switch ( bs ) {
- case press: ls = mbh.channel_right_press( button ); break;
- case release: ls = mbh.channel_right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x32: // flip
- switch ( bs ) {
- case press: ls = mbh.flip_press( button ); break;
- case release: ls = mbh.flip_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x33: // edit
- switch ( bs ) {
- case press: ls = mbh.edit_press( button ); break;
- case release: ls = mbh.edit_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x34: // name_value
- switch ( bs ) {
- case press: ls = mbh.name_value_press( button ); break;
- case release: ls = mbh.name_value_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x35: // smpte_beats
- switch ( bs ) {
- case press: ls = mbh.smpte_beats_press( button ); break;
- case release: ls = mbh.smpte_beats_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x36: // F1
- switch ( bs ) {
- case press: ls = mbh.F1_press( button ); break;
- case release: ls = mbh.F1_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x37: // F2
- switch ( bs ) {
- case press: ls = mbh.F2_press( button ); break;
- case release: ls = mbh.F2_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x38: // F3
- switch ( bs ) {
- case press: ls = mbh.F3_press( button ); break;
- case release: ls = mbh.F3_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x39: // F4
- switch ( bs ) {
- case press: ls = mbh.F4_press( button ); break;
- case release: ls = mbh.F4_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3a: // F5
- switch ( bs ) {
- case press: ls = mbh.F5_press( button ); break;
- case release: ls = mbh.F5_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3b: // F6
- switch ( bs ) {
- case press: ls = mbh.F6_press( button ); break;
- case release: ls = mbh.F6_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3c: // F7
- switch ( bs ) {
- case press: ls = mbh.F7_press( button ); break;
- case release: ls = mbh.F7_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3d: // F8
- switch ( bs ) {
- case press: ls = mbh.F8_press( button ); break;
- case release: ls = mbh.F8_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3e: // F9
- switch ( bs ) {
- case press: ls = mbh.F9_press( button ); break;
- case release: ls = mbh.F9_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x3f: // F10
- switch ( bs ) {
- case press: ls = mbh.F10_press( button ); break;
- case release: ls = mbh.F10_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x40: // F11
- switch ( bs ) {
- case press: ls = mbh.F11_press( button ); break;
- case release: ls = mbh.F11_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x41: // F12
- switch ( bs ) {
- case press: ls = mbh.F12_press( button ); break;
- case release: ls = mbh.F12_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x42: // F13
- switch ( bs ) {
- case press: ls = mbh.F13_press( button ); break;
- case release: ls = mbh.F13_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x43: // F14
- switch ( bs ) {
- case press: ls = mbh.F14_press( button ); break;
- case release: ls = mbh.F14_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x44: // F15
- switch ( bs ) {
- case press: ls = mbh.F15_press( button ); break;
- case release: ls = mbh.F15_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x45: // F16
- switch ( bs ) {
- case press: ls = mbh.F16_press( button ); break;
- case release: ls = mbh.F16_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x46: // shift
- switch ( bs ) {
- case press: ls = mbh.shift_press( button ); break;
- case release: ls = mbh.shift_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x47: // option
- switch ( bs ) {
- case press: ls = mbh.option_press( button ); break;
- case release: ls = mbh.option_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x48: // control
- switch ( bs ) {
- case press: ls = mbh.control_press( button ); break;
- case release: ls = mbh.control_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x49: // cmd_alt
- switch ( bs ) {
- case press: ls = mbh.cmd_alt_press( button ); break;
- case release: ls = mbh.cmd_alt_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4a: // on
- switch ( bs ) {
- case press: ls = mbh.on_press( button ); break;
- case release: ls = mbh.on_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4b: // rec_ready
- switch ( bs ) {
- case press: ls = mbh.rec_ready_press( button ); break;
- case release: ls = mbh.rec_ready_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4c: // undo
- switch ( bs ) {
- case press: ls = mbh.undo_press( button ); break;
- case release: ls = mbh.undo_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4d: // snapshot
- switch ( bs ) {
- case press: ls = mbh.snapshot_press( button ); break;
- case release: ls = mbh.snapshot_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4e: // touch
- switch ( bs ) {
- case press: ls = mbh.touch_press( button ); break;
- case release: ls = mbh.touch_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x4f: // redo
- switch ( bs ) {
- case press: ls = mbh.redo_press( button ); break;
- case release: ls = mbh.redo_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x50: // marker
- switch ( bs ) {
- case press: ls = mbh.marker_press( button ); break;
- case release: ls = mbh.marker_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x51: // enter
- switch ( bs ) {
- case press: ls = mbh.enter_press( button ); break;
- case release: ls = mbh.enter_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x52: // cancel
- switch ( bs ) {
- case press: ls = mbh.cancel_press( button ); break;
- case release: ls = mbh.cancel_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x53: // mixer
- switch ( bs ) {
- case press: ls = mbh.mixer_press( button ); break;
- case release: ls = mbh.mixer_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x54: // frm_left
- switch ( bs ) {
- case press: ls = mbh.frm_left_press( button ); break;
- case release: ls = mbh.frm_left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x55: // frm_right
- switch ( bs ) {
- case press: ls = mbh.frm_right_press( button ); break;
- case release: ls = mbh.frm_right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x56: // loop
- switch ( bs ) {
- case press: ls = mbh.loop_press( button ); break;
- case release: ls = mbh.loop_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x57: // punch_in
- switch ( bs ) {
- case press: ls = mbh.punch_in_press( button ); break;
- case release: ls = mbh.punch_in_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x58: // punch_out
- switch ( bs ) {
- case press: ls = mbh.punch_out_press( button ); break;
- case release: ls = mbh.punch_out_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x59: // home
- switch ( bs ) {
- case press: ls = mbh.home_press( button ); break;
- case release: ls = mbh.home_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5a: // end
- switch ( bs ) {
- case press: ls = mbh.end_press( button ); break;
- case release: ls = mbh.end_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5b: // rewind
- switch ( bs ) {
- case press: ls = mbh.rewind_press( button ); break;
- case release: ls = mbh.rewind_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5c: // ffwd
- switch ( bs ) {
- case press: ls = mbh.ffwd_press( button ); break;
- case release: ls = mbh.ffwd_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5d: // stop
- switch ( bs ) {
- case press: ls = mbh.stop_press( button ); break;
- case release: ls = mbh.stop_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5e: // play
- switch ( bs ) {
- case press: ls = mbh.play_press( button ); break;
- case release: ls = mbh.play_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x5f: // record
- switch ( bs ) {
- case press: ls = mbh.record_press( button ); break;
- case release: ls = mbh.record_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x60: // cursor_up
- switch ( bs ) {
- case press: ls = mbh.cursor_up_press( button ); break;
- case release: ls = mbh.cursor_up_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x61: // cursor_down
- switch ( bs ) {
- case press: ls = mbh.cursor_down_press( button ); break;
- case release: ls = mbh.cursor_down_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x62: // cursor_left
- switch ( bs ) {
- case press: ls = mbh.cursor_left_press( button ); break;
- case release: ls = mbh.cursor_left_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x63: // cursor_right
- switch ( bs ) {
- case press: ls = mbh.cursor_right_press( button ); break;
- case release: ls = mbh.cursor_right_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x64: // zoom
- switch ( bs ) {
- case press: ls = mbh.zoom_press( button ); break;
- case release: ls = mbh.zoom_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x65: // scrub
- switch ( bs ) {
- case press: ls = mbh.scrub_press( button ); break;
- case release: ls = mbh.scrub_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x66: // user_a
- switch ( bs ) {
- case press: ls = mbh.user_a_press( button ); break;
- case release: ls = mbh.user_a_release( button ); break;
- case neither: break;
- }
- break;
-
- case 0x67: // user_b
- switch ( bs ) {
- case press: ls = mbh.user_b_press( button ); break;
- case release: ls = mbh.user_b_release( button ); break;
- case neither: break;
- }
- break;
-
- }
- mbh.update_led( button, ls );
+ return state.sign * ( std::pow( float(state.ticks + 1), 2 ) + current_speed ) / 100.0;
}
diff --git a/libs/surfaces/mackie/mackie_surface.h b/libs/surfaces/mackie/mackie_surface.h
index 735cbc5851..b3bfb3b6d4 100644
--- a/libs/surfaces/mackie/mackie_surface.h
+++ b/libs/surfaces/mackie/mackie_surface.h
@@ -10,7 +10,6 @@ namespace Mackie
{
class MackieButtonHandler;
-
class MackieSurface : public Surface
{
public:
@@ -20,6 +19,12 @@ public:
virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
virtual void init_controls();
+
+ virtual bool has_timecode_display() const { return true; }
+ virtual void display_timecode( SurfacePort &, MackieMidiBuilder &, const std::string & timecode, const std::string & timecode_last );
+
+ virtual float scrub_scaling_factor() { return 100.0; }
+ virtual float scaled_delta( const ControlState & state, float current_speed );
};
}
diff --git a/libs/surfaces/mackie/mackie_surface_generated.cc b/libs/surfaces/mackie/mackie_surface_generated.cc
new file mode 100644
index 0000000000..f284a05142
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_surface_generated.cc
@@ -0,0 +1,1507 @@
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "mackie_surface.h"
+
+#include "controls.h"
+#include "mackie_button_handler.h"
+
+using namespace Mackie;
+
+void Mackie::MackieSurface::init_controls()
+{
+ // intialise groups and strips
+ Group * group = 0;
+
+ // make sure there are enough strips
+ strips.resize( 8 );
+
+ group = new Group ( "user" );
+ groups["user"] = group;
+
+ group = new Group ( "assignment" );
+ groups["assignment"] = group;
+
+ group = new Group ( "none" );
+ groups["none"] = group;
+
+ group = new MasterStrip ( "master", 0 );
+ groups["master"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_1", 0 );
+ groups["strip_1"] = group;
+ strips[0] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "cursor" );
+ groups["cursor"] = group;
+
+ group = new Strip ( "strip_2", 1 );
+ groups["strip_2"] = group;
+ strips[1] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "functions" );
+ groups["functions"] = group;
+
+ group = new Group ( "automation" );
+ groups["automation"] = group;
+
+ group = new Strip ( "strip_3", 2 );
+ groups["strip_3"] = group;
+ strips[2] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "display" );
+ groups["display"] = group;
+
+ group = new Strip ( "strip_4", 3 );
+ groups["strip_4"] = group;
+ strips[3] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_5", 4 );
+ groups["strip_5"] = group;
+ strips[4] = dynamic_cast<Strip*>( group );
+
+ group = new Strip ( "strip_6", 5 );
+ groups["strip_6"] = group;
+ strips[5] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "transport" );
+ groups["transport"] = group;
+
+ group = new Strip ( "strip_7", 6 );
+ groups["strip_7"] = group;
+ strips[6] = dynamic_cast<Strip*>( group );
+
+ group = new Group ( "modifiers" );
+ groups["modifiers"] = group;
+
+ group = new Group ( "bank" );
+ groups["bank"] = group;
+
+ group = new Strip ( "strip_8", 7 );
+ groups["strip_8"] = group;
+ strips[7] = dynamic_cast<Strip*>( group );
+
+
+ // initialise controls
+ Fader * fader = 0;
+ Pot * pot = 0;
+ Button * button = 0;
+ Led * led = 0;
+
+ group = groups["strip_1"];
+ fader = new Fader ( 0, 1, "gain", *group );
+ faders[0x00] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_2"];
+ fader = new Fader ( 1, 2, "gain", *group );
+ faders[0x01] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_3"];
+ fader = new Fader ( 2, 3, "gain", *group );
+ faders[0x02] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_4"];
+ fader = new Fader ( 3, 4, "gain", *group );
+ faders[0x03] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_5"];
+ fader = new Fader ( 4, 5, "gain", *group );
+ faders[0x04] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_6"];
+ fader = new Fader ( 5, 6, "gain", *group );
+ faders[0x05] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_7"];
+ fader = new Fader ( 6, 7, "gain", *group );
+ faders[0x06] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_8"];
+ fader = new Fader ( 7, 8, "gain", *group );
+ faders[0x07] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["master"];
+ fader = new Fader ( 8, 1, "gain", *group );
+ faders[0x08] = fader;
+ controls.push_back( fader );
+ group->add( *fader );
+
+ group = groups["strip_1"];
+ pot = new Pot ( 16, 1, "vpot", *group );
+ pots[0x10] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_2"];
+ pot = new Pot ( 17, 2, "vpot", *group );
+ pots[0x11] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_3"];
+ pot = new Pot ( 18, 3, "vpot", *group );
+ pots[0x12] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_4"];
+ pot = new Pot ( 19, 4, "vpot", *group );
+ pots[0x13] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_5"];
+ pot = new Pot ( 20, 5, "vpot", *group );
+ pots[0x14] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_6"];
+ pot = new Pot ( 21, 6, "vpot", *group );
+ pots[0x15] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_7"];
+ pot = new Pot ( 22, 7, "vpot", *group );
+ pots[0x16] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["strip_8"];
+ pot = new Pot ( 23, 8, "vpot", *group );
+ pots[0x17] = pot;
+ controls.push_back( pot );
+ group->add( *pot );
+
+ group = groups["none"];
+ pot = new Jog ( 60, 1, "jog", *group );
+ pots[0x3c] = pot;
+ controls.push_back( pot );
+ controls_by_name["jog"] = pot;
+ group->add( *pot );
+
+ group = groups["none"];
+ pot = new Pot ( 46, 1, "external", *group );
+ pots[0x2e] = pot;
+ controls.push_back( pot );
+ controls_by_name["external"] = pot;
+ group->add( *pot );
+
+ group = groups["strip_1"];
+ button = new Button ( 0, 1, "recenable", *group );
+ buttons[0x00] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 1, 2, "recenable", *group );
+ buttons[0x01] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 2, 3, "recenable", *group );
+ buttons[0x02] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 3, 4, "recenable", *group );
+ buttons[0x03] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 4, 5, "recenable", *group );
+ buttons[0x04] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 5, 6, "recenable", *group );
+ buttons[0x05] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 6, 7, "recenable", *group );
+ buttons[0x06] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_8"];
+ button = new Button ( 7, 8, "recenable", *group );
+ buttons[0x07] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 8, 1, "solo", *group );
+ buttons[0x08] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 9, 2, "solo", *group );
+ buttons[0x09] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 10, 3, "solo", *group );
+ buttons[0x0a] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 11, 4, "solo", *group );
+ buttons[0x0b] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 12, 5, "solo", *group );
+ buttons[0x0c] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 13, 6, "solo", *group );
+ buttons[0x0d] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 14, 7, "solo", *group );
+ buttons[0x0e] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_8"];
+ button = new Button ( 15, 8, "solo", *group );
+ buttons[0x0f] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 16, 1, "mute", *group );
+ buttons[0x10] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 17, 2, "mute", *group );
+ buttons[0x11] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 18, 3, "mute", *group );
+ buttons[0x12] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 19, 4, "mute", *group );
+ buttons[0x13] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 20, 5, "mute", *group );
+ buttons[0x14] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 21, 6, "mute", *group );
+ buttons[0x15] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 22, 7, "mute", *group );
+ buttons[0x16] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_8"];
+ button = new Button ( 23, 8, "mute", *group );
+ buttons[0x17] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 24, 1, "select", *group );
+ buttons[0x18] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 25, 2, "select", *group );
+ buttons[0x19] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 26, 3, "select", *group );
+ buttons[0x1a] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 27, 4, "select", *group );
+ buttons[0x1b] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 28, 5, "select", *group );
+ buttons[0x1c] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 29, 6, "select", *group );
+ buttons[0x1d] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 30, 7, "select", *group );
+ buttons[0x1e] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_8"];
+ button = new Button ( 31, 8, "select", *group );
+ buttons[0x1f] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 32, 1, "vselect", *group );
+ buttons[0x20] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 33, 2, "vselect", *group );
+ buttons[0x21] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 34, 3, "vselect", *group );
+ buttons[0x22] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 35, 4, "vselect", *group );
+ buttons[0x23] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 36, 5, "vselect", *group );
+ buttons[0x24] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 37, 6, "vselect", *group );
+ buttons[0x25] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 38, 7, "vselect", *group );
+ buttons[0x26] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_8"];
+ button = new Button ( 39, 8, "vselect", *group );
+ buttons[0x27] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 40, 1, "io", *group );
+ buttons[0x28] = button;
+ controls.push_back( button );
+ controls_by_name["io"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 41, 1, "sends", *group );
+ buttons[0x29] = button;
+ controls.push_back( button );
+ controls_by_name["sends"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 42, 1, "pan", *group );
+ buttons[0x2a] = button;
+ controls.push_back( button );
+ controls_by_name["pan"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 43, 1, "plugin", *group );
+ buttons[0x2b] = button;
+ controls.push_back( button );
+ controls_by_name["plugin"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 44, 1, "eq", *group );
+ buttons[0x2c] = button;
+ controls.push_back( button );
+ controls_by_name["eq"] = button;
+ group->add( *button );
+
+ group = groups["assignment"];
+ button = new Button ( 45, 1, "dyn", *group );
+ buttons[0x2d] = button;
+ controls.push_back( button );
+ controls_by_name["dyn"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 46, 1, "left", *group );
+ buttons[0x2e] = button;
+ controls.push_back( button );
+ controls_by_name["left"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 47, 1, "right", *group );
+ buttons[0x2f] = button;
+ controls.push_back( button );
+ controls_by_name["right"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 48, 1, "channel_left", *group );
+ buttons[0x30] = button;
+ controls.push_back( button );
+ controls_by_name["channel_left"] = button;
+ group->add( *button );
+
+ group = groups["bank"];
+ button = new Button ( 49, 1, "channel_right", *group );
+ buttons[0x31] = button;
+ controls.push_back( button );
+ controls_by_name["channel_right"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 50, 1, "flip", *group );
+ buttons[0x32] = button;
+ controls.push_back( button );
+ controls_by_name["flip"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 51, 1, "edit", *group );
+ buttons[0x33] = button;
+ controls.push_back( button );
+ controls_by_name["edit"] = button;
+ group->add( *button );
+
+ group = groups["display"];
+ button = new Button ( 52, 1, "name_value", *group );
+ buttons[0x34] = button;
+ controls.push_back( button );
+ controls_by_name["name_value"] = button;
+ group->add( *button );
+
+ group = groups["display"];
+ button = new Button ( 53, 1, "smpte_beats", *group );
+ buttons[0x35] = button;
+ controls.push_back( button );
+ controls_by_name["smpte_beats"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 54, 1, "F1", *group );
+ buttons[0x36] = button;
+ controls.push_back( button );
+ controls_by_name["F1"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 55, 1, "F2", *group );
+ buttons[0x37] = button;
+ controls.push_back( button );
+ controls_by_name["F2"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 56, 1, "F3", *group );
+ buttons[0x38] = button;
+ controls.push_back( button );
+ controls_by_name["F3"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 57, 1, "F4", *group );
+ buttons[0x39] = button;
+ controls.push_back( button );
+ controls_by_name["F4"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 58, 1, "F5", *group );
+ buttons[0x3a] = button;
+ controls.push_back( button );
+ controls_by_name["F5"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 59, 1, "F6", *group );
+ buttons[0x3b] = button;
+ controls.push_back( button );
+ controls_by_name["F6"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 60, 1, "F7", *group );
+ buttons[0x3c] = button;
+ controls.push_back( button );
+ controls_by_name["F7"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 61, 1, "F8", *group );
+ buttons[0x3d] = button;
+ controls.push_back( button );
+ controls_by_name["F8"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 62, 1, "F9", *group );
+ buttons[0x3e] = button;
+ controls.push_back( button );
+ controls_by_name["F9"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 63, 1, "F10", *group );
+ buttons[0x3f] = button;
+ controls.push_back( button );
+ controls_by_name["F10"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 64, 1, "F11", *group );
+ buttons[0x40] = button;
+ controls.push_back( button );
+ controls_by_name["F11"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 65, 1, "F12", *group );
+ buttons[0x41] = button;
+ controls.push_back( button );
+ controls_by_name["F12"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 66, 1, "F13", *group );
+ buttons[0x42] = button;
+ controls.push_back( button );
+ controls_by_name["F13"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 67, 1, "F14", *group );
+ buttons[0x43] = button;
+ controls.push_back( button );
+ controls_by_name["F14"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 68, 1, "F15", *group );
+ buttons[0x44] = button;
+ controls.push_back( button );
+ controls_by_name["F15"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 69, 1, "F16", *group );
+ buttons[0x45] = button;
+ controls.push_back( button );
+ controls_by_name["F16"] = button;
+ group->add( *button );
+
+ group = groups["modifiers"];
+ button = new Button ( 70, 1, "shift", *group );
+ buttons[0x46] = button;
+ controls.push_back( button );
+ controls_by_name["shift"] = button;
+ group->add( *button );
+
+ group = groups["modifiers"];
+ button = new Button ( 71, 1, "option", *group );
+ buttons[0x47] = button;
+ controls.push_back( button );
+ controls_by_name["option"] = button;
+ group->add( *button );
+
+ group = groups["modifiers"];
+ button = new Button ( 72, 1, "control", *group );
+ buttons[0x48] = button;
+ controls.push_back( button );
+ controls_by_name["control"] = button;
+ group->add( *button );
+
+ group = groups["modifiers"];
+ button = new Button ( 73, 1, "cmd_alt", *group );
+ buttons[0x49] = button;
+ controls.push_back( button );
+ controls_by_name["cmd_alt"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 74, 1, "on", *group );
+ buttons[0x4a] = button;
+ controls.push_back( button );
+ controls_by_name["on"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 75, 1, "rec_ready", *group );
+ buttons[0x4b] = button;
+ controls.push_back( button );
+ controls_by_name["rec_ready"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 76, 1, "undo", *group );
+ buttons[0x4c] = button;
+ controls.push_back( button );
+ controls_by_name["undo"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 77, 1, "snapshot", *group );
+ buttons[0x4d] = button;
+ controls.push_back( button );
+ controls_by_name["snapshot"] = button;
+ group->add( *button );
+
+ group = groups["automation"];
+ button = new Button ( 78, 1, "touch", *group );
+ buttons[0x4e] = button;
+ controls.push_back( button );
+ controls_by_name["touch"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 79, 1, "redo", *group );
+ buttons[0x4f] = button;
+ controls.push_back( button );
+ controls_by_name["redo"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 80, 1, "marker", *group );
+ buttons[0x50] = button;
+ controls.push_back( button );
+ controls_by_name["marker"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 81, 1, "enter", *group );
+ buttons[0x51] = button;
+ controls.push_back( button );
+ controls_by_name["enter"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 82, 1, "cancel", *group );
+ buttons[0x52] = button;
+ controls.push_back( button );
+ controls_by_name["cancel"] = button;
+ group->add( *button );
+
+ group = groups["functions"];
+ button = new Button ( 83, 1, "mixer", *group );
+ buttons[0x53] = button;
+ controls.push_back( button );
+ controls_by_name["mixer"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 84, 1, "frm_left", *group );
+ buttons[0x54] = button;
+ controls.push_back( button );
+ controls_by_name["frm_left"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 85, 1, "frm_right", *group );
+ buttons[0x55] = button;
+ controls.push_back( button );
+ controls_by_name["frm_right"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 86, 1, "loop", *group );
+ buttons[0x56] = button;
+ controls.push_back( button );
+ controls_by_name["loop"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 87, 1, "punch_in", *group );
+ buttons[0x57] = button;
+ controls.push_back( button );
+ controls_by_name["punch_in"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 88, 1, "punch_out", *group );
+ buttons[0x58] = button;
+ controls.push_back( button );
+ controls_by_name["punch_out"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 89, 1, "home", *group );
+ buttons[0x59] = button;
+ controls.push_back( button );
+ controls_by_name["home"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 90, 1, "end", *group );
+ buttons[0x5a] = button;
+ controls.push_back( button );
+ controls_by_name["end"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 91, 1, "rewind", *group );
+ buttons[0x5b] = button;
+ controls.push_back( button );
+ controls_by_name["rewind"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 92, 1, "ffwd", *group );
+ buttons[0x5c] = button;
+ controls.push_back( button );
+ controls_by_name["ffwd"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 93, 1, "stop", *group );
+ buttons[0x5d] = button;
+ controls.push_back( button );
+ controls_by_name["stop"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 94, 1, "play", *group );
+ buttons[0x5e] = button;
+ controls.push_back( button );
+ controls_by_name["play"] = button;
+ group->add( *button );
+
+ group = groups["transport"];
+ button = new Button ( 95, 1, "record", *group );
+ buttons[0x5f] = button;
+ controls.push_back( button );
+ controls_by_name["record"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 96, 1, "cursor_up", *group );
+ buttons[0x60] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_up"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 97, 1, "cursor_down", *group );
+ buttons[0x61] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_down"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 98, 1, "cursor_left", *group );
+ buttons[0x62] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_left"] = button;
+ group->add( *button );
+
+ group = groups["cursor"];
+ button = new Button ( 99, 1, "cursor_right", *group );
+ buttons[0x63] = button;
+ controls.push_back( button );
+ controls_by_name["cursor_right"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 100, 1, "zoom", *group );
+ buttons[0x64] = button;
+ controls.push_back( button );
+ controls_by_name["zoom"] = button;
+ group->add( *button );
+
+ group = groups["none"];
+ button = new Button ( 101, 1, "scrub", *group );
+ buttons[0x65] = button;
+ controls.push_back( button );
+ controls_by_name["scrub"] = button;
+ group->add( *button );
+
+ group = groups["user"];
+ button = new Button ( 102, 1, "user_a", *group );
+ buttons[0x66] = button;
+ controls.push_back( button );
+ controls_by_name["user_a"] = button;
+ group->add( *button );
+
+ group = groups["user"];
+ button = new Button ( 103, 1, "user_b", *group );
+ buttons[0x67] = button;
+ controls.push_back( button );
+ controls_by_name["user_b"] = button;
+ group->add( *button );
+
+ group = groups["strip_1"];
+ button = new Button ( 104, 1, "fader_touch", *group );
+ buttons[0x68] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_2"];
+ button = new Button ( 105, 2, "fader_touch", *group );
+ buttons[0x69] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_3"];
+ button = new Button ( 106, 3, "fader_touch", *group );
+ buttons[0x6a] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_4"];
+ button = new Button ( 107, 4, "fader_touch", *group );
+ buttons[0x6b] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_5"];
+ button = new Button ( 108, 5, "fader_touch", *group );
+ buttons[0x6c] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_6"];
+ button = new Button ( 109, 6, "fader_touch", *group );
+ buttons[0x6d] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_7"];
+ button = new Button ( 110, 7, "fader_touch", *group );
+ buttons[0x6e] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["strip_8"];
+ button = new Button ( 111, 8, "fader_touch", *group );
+ buttons[0x6f] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["master"];
+ button = new Button ( 112, 1, "fader_touch", *group );
+ buttons[0x70] = button;
+ controls.push_back( button );
+ group->add( *button );
+
+ group = groups["none"];
+ led = new Led ( 113, 1, "smpte", *group );
+ leds[0x71] = led;
+ controls.push_back( led );
+ controls_by_name["smpte"] = led;
+ group->add( *led );
+
+ group = groups["none"];
+ led = new Led ( 114, 1, "beats", *group );
+ leds[0x72] = led;
+ controls.push_back( led );
+ controls_by_name["beats"] = led;
+ group->add( *led );
+
+ group = groups["none"];
+ led = new Led ( 115, 1, "solo", *group );
+ leds[0x73] = led;
+ controls.push_back( led );
+ controls_by_name["solo"] = led;
+ group->add( *led );
+
+ group = groups["none"];
+ led = new Led ( 118, 1, "relay_click", *group );
+ leds[0x76] = led;
+ controls.push_back( led );
+ controls_by_name["relay_click"] = led;
+ group->add( *led );
+
+}
+
+void Mackie::MackieSurface::handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button )
+{
+ if ( bs != press && bs != release )
+ {
+ mbh.update_led( button, none );
+ return;
+ }
+
+ LedState ls;
+ switch ( button.id() )
+ {
+
+ case 0x9028: // io
+ switch ( bs ) {
+ case press: ls = mbh.io_press( button ); break;
+ case release: ls = mbh.io_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9029: // sends
+ switch ( bs ) {
+ case press: ls = mbh.sends_press( button ); break;
+ case release: ls = mbh.sends_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902a: // pan
+ switch ( bs ) {
+ case press: ls = mbh.pan_press( button ); break;
+ case release: ls = mbh.pan_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902b: // plugin
+ switch ( bs ) {
+ case press: ls = mbh.plugin_press( button ); break;
+ case release: ls = mbh.plugin_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902c: // eq
+ switch ( bs ) {
+ case press: ls = mbh.eq_press( button ); break;
+ case release: ls = mbh.eq_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902d: // dyn
+ switch ( bs ) {
+ case press: ls = mbh.dyn_press( button ); break;
+ case release: ls = mbh.dyn_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902e: // left
+ switch ( bs ) {
+ case press: ls = mbh.left_press( button ); break;
+ case release: ls = mbh.left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x902f: // right
+ switch ( bs ) {
+ case press: ls = mbh.right_press( button ); break;
+ case release: ls = mbh.right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9030: // channel_left
+ switch ( bs ) {
+ case press: ls = mbh.channel_left_press( button ); break;
+ case release: ls = mbh.channel_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9031: // channel_right
+ switch ( bs ) {
+ case press: ls = mbh.channel_right_press( button ); break;
+ case release: ls = mbh.channel_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9032: // flip
+ switch ( bs ) {
+ case press: ls = mbh.flip_press( button ); break;
+ case release: ls = mbh.flip_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9033: // edit
+ switch ( bs ) {
+ case press: ls = mbh.edit_press( button ); break;
+ case release: ls = mbh.edit_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9034: // name_value
+ switch ( bs ) {
+ case press: ls = mbh.name_value_press( button ); break;
+ case release: ls = mbh.name_value_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9035: // smpte_beats
+ switch ( bs ) {
+ case press: ls = mbh.smpte_beats_press( button ); break;
+ case release: ls = mbh.smpte_beats_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9036: // F1
+ switch ( bs ) {
+ case press: ls = mbh.F1_press( button ); break;
+ case release: ls = mbh.F1_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9037: // F2
+ switch ( bs ) {
+ case press: ls = mbh.F2_press( button ); break;
+ case release: ls = mbh.F2_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9038: // F3
+ switch ( bs ) {
+ case press: ls = mbh.F3_press( button ); break;
+ case release: ls = mbh.F3_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9039: // F4
+ switch ( bs ) {
+ case press: ls = mbh.F4_press( button ); break;
+ case release: ls = mbh.F4_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903a: // F5
+ switch ( bs ) {
+ case press: ls = mbh.F5_press( button ); break;
+ case release: ls = mbh.F5_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903b: // F6
+ switch ( bs ) {
+ case press: ls = mbh.F6_press( button ); break;
+ case release: ls = mbh.F6_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903c: // F7
+ switch ( bs ) {
+ case press: ls = mbh.F7_press( button ); break;
+ case release: ls = mbh.F7_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903d: // F8
+ switch ( bs ) {
+ case press: ls = mbh.F8_press( button ); break;
+ case release: ls = mbh.F8_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903e: // F9
+ switch ( bs ) {
+ case press: ls = mbh.F9_press( button ); break;
+ case release: ls = mbh.F9_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x903f: // F10
+ switch ( bs ) {
+ case press: ls = mbh.F10_press( button ); break;
+ case release: ls = mbh.F10_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9040: // F11
+ switch ( bs ) {
+ case press: ls = mbh.F11_press( button ); break;
+ case release: ls = mbh.F11_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9041: // F12
+ switch ( bs ) {
+ case press: ls = mbh.F12_press( button ); break;
+ case release: ls = mbh.F12_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9042: // F13
+ switch ( bs ) {
+ case press: ls = mbh.F13_press( button ); break;
+ case release: ls = mbh.F13_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9043: // F14
+ switch ( bs ) {
+ case press: ls = mbh.F14_press( button ); break;
+ case release: ls = mbh.F14_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9044: // F15
+ switch ( bs ) {
+ case press: ls = mbh.F15_press( button ); break;
+ case release: ls = mbh.F15_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9045: // F16
+ switch ( bs ) {
+ case press: ls = mbh.F16_press( button ); break;
+ case release: ls = mbh.F16_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9046: // shift
+ switch ( bs ) {
+ case press: ls = mbh.shift_press( button ); break;
+ case release: ls = mbh.shift_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9047: // option
+ switch ( bs ) {
+ case press: ls = mbh.option_press( button ); break;
+ case release: ls = mbh.option_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9048: // control
+ switch ( bs ) {
+ case press: ls = mbh.control_press( button ); break;
+ case release: ls = mbh.control_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9049: // cmd_alt
+ switch ( bs ) {
+ case press: ls = mbh.cmd_alt_press( button ); break;
+ case release: ls = mbh.cmd_alt_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904a: // on
+ switch ( bs ) {
+ case press: ls = mbh.on_press( button ); break;
+ case release: ls = mbh.on_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904b: // rec_ready
+ switch ( bs ) {
+ case press: ls = mbh.rec_ready_press( button ); break;
+ case release: ls = mbh.rec_ready_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904c: // undo
+ switch ( bs ) {
+ case press: ls = mbh.undo_press( button ); break;
+ case release: ls = mbh.undo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904d: // snapshot
+ switch ( bs ) {
+ case press: ls = mbh.snapshot_press( button ); break;
+ case release: ls = mbh.snapshot_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904e: // touch
+ switch ( bs ) {
+ case press: ls = mbh.touch_press( button ); break;
+ case release: ls = mbh.touch_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x904f: // redo
+ switch ( bs ) {
+ case press: ls = mbh.redo_press( button ); break;
+ case release: ls = mbh.redo_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9050: // marker
+ switch ( bs ) {
+ case press: ls = mbh.marker_press( button ); break;
+ case release: ls = mbh.marker_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9051: // enter
+ switch ( bs ) {
+ case press: ls = mbh.enter_press( button ); break;
+ case release: ls = mbh.enter_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9052: // cancel
+ switch ( bs ) {
+ case press: ls = mbh.cancel_press( button ); break;
+ case release: ls = mbh.cancel_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9053: // mixer
+ switch ( bs ) {
+ case press: ls = mbh.mixer_press( button ); break;
+ case release: ls = mbh.mixer_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9054: // frm_left
+ switch ( bs ) {
+ case press: ls = mbh.frm_left_press( button ); break;
+ case release: ls = mbh.frm_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9055: // frm_right
+ switch ( bs ) {
+ case press: ls = mbh.frm_right_press( button ); break;
+ case release: ls = mbh.frm_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9056: // loop
+ switch ( bs ) {
+ case press: ls = mbh.loop_press( button ); break;
+ case release: ls = mbh.loop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9057: // punch_in
+ switch ( bs ) {
+ case press: ls = mbh.punch_in_press( button ); break;
+ case release: ls = mbh.punch_in_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9058: // punch_out
+ switch ( bs ) {
+ case press: ls = mbh.punch_out_press( button ); break;
+ case release: ls = mbh.punch_out_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9059: // home
+ switch ( bs ) {
+ case press: ls = mbh.home_press( button ); break;
+ case release: ls = mbh.home_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905a: // end
+ switch ( bs ) {
+ case press: ls = mbh.end_press( button ); break;
+ case release: ls = mbh.end_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905b: // rewind
+ switch ( bs ) {
+ case press: ls = mbh.rewind_press( button ); break;
+ case release: ls = mbh.rewind_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905c: // ffwd
+ switch ( bs ) {
+ case press: ls = mbh.ffwd_press( button ); break;
+ case release: ls = mbh.ffwd_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905d: // stop
+ switch ( bs ) {
+ case press: ls = mbh.stop_press( button ); break;
+ case release: ls = mbh.stop_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905e: // play
+ switch ( bs ) {
+ case press: ls = mbh.play_press( button ); break;
+ case release: ls = mbh.play_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x905f: // record
+ switch ( bs ) {
+ case press: ls = mbh.record_press( button ); break;
+ case release: ls = mbh.record_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9060: // cursor_up
+ switch ( bs ) {
+ case press: ls = mbh.cursor_up_press( button ); break;
+ case release: ls = mbh.cursor_up_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9061: // cursor_down
+ switch ( bs ) {
+ case press: ls = mbh.cursor_down_press( button ); break;
+ case release: ls = mbh.cursor_down_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9062: // cursor_left
+ switch ( bs ) {
+ case press: ls = mbh.cursor_left_press( button ); break;
+ case release: ls = mbh.cursor_left_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9063: // cursor_right
+ switch ( bs ) {
+ case press: ls = mbh.cursor_right_press( button ); break;
+ case release: ls = mbh.cursor_right_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9064: // zoom
+ switch ( bs ) {
+ case press: ls = mbh.zoom_press( button ); break;
+ case release: ls = mbh.zoom_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9065: // scrub
+ switch ( bs ) {
+ case press: ls = mbh.scrub_press( button ); break;
+ case release: ls = mbh.scrub_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9066: // user_a
+ switch ( bs ) {
+ case press: ls = mbh.user_a_press( button ); break;
+ case release: ls = mbh.user_a_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ case 0x9067: // user_b
+ switch ( bs ) {
+ case press: ls = mbh.user_b_press( button ); break;
+ case release: ls = mbh.user_b_release( button ); break;
+ case neither: break;
+ }
+ break;
+
+ }
+ mbh.update_led( button, ls );
+}
diff --git a/libs/surfaces/mackie/midi_byte_array.cc b/libs/surfaces/mackie/midi_byte_array.cc
index 192af6a1ce..1c27c82be1 100644
--- a/libs/surfaces/mackie/midi_byte_array.cc
+++ b/libs/surfaces/mackie/midi_byte_array.cc
@@ -24,6 +24,7 @@
#include <algorithm>
#include <cstdarg>
#include <iomanip>
+#include <stdexcept>
using namespace std;
@@ -96,3 +97,12 @@ ostream & operator << ( ostream & os, const MidiByteArray & mba )
os << "]";
return os;
}
+
+MidiByteArray & operator << ( MidiByteArray & mba, const std::string & st )
+{
+ for ( string::const_iterator it = st.begin(); it != st.end(); ++it )
+ {
+ mba << *it;
+ }
+ return mba;
+}
diff --git a/libs/surfaces/mackie/midi_byte_array.h b/libs/surfaces/mackie/midi_byte_array.h
index e77ece1b88..7176367189 100644
--- a/libs/surfaces/mackie/midi_byte_array.h
+++ b/libs/surfaces/mackie/midi_byte_array.h
@@ -67,6 +67,9 @@ public:
/// 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 );
diff --git a/libs/surfaces/mackie/route_signal.cc b/libs/surfaces/mackie/route_signal.cc
index c21d326fef..33a8908dde 100644
--- a/libs/surfaces/mackie/route_signal.cc
+++ b/libs/surfaces/mackie/route_signal.cc
@@ -20,37 +20,41 @@
#include <ardour/route.h>
#include <ardour/track.h>
#include <ardour/panner.h>
-#include <ardour/types.h>
#include "mackie_control_protocol.h"
#include <stdexcept>
using namespace Mackie;
+using namespace std;
void RouteSignal::connect()
{
+ back_insert_iterator<Connections> cins = back_inserter( _connections );
+
if ( _strip.has_solo() )
- _solo_changed_connection = _route.solo_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) );
+ cins = _route.solo_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_solo_changed ), this ) );
if ( _strip.has_mute() )
- _mute_changed_connection = _route.mute_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) );
+ cins = _route.mute_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_mute_changed ), this ) );
if ( _strip.has_gain() )
- _gain_changed_connection = _route.gain_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) );
+ cins = _route.gain_control()->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this, true ) );
- _name_changed_connection = _route.NameChanged.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
+ cins = _route.NameChanged.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
- if ( _route.panner().npanners() == 1 )
+ cins = _route.panner().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_panner_changed ), this, true ) );
+ for ( unsigned int i = 0; i < _route.panner().npanners(); ++i )
{
- _panner_changed_connection = _route.panner().pan_control(0)->Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_panner_changed ), this ) );
+ cins = _route.panner().streampanner (i).Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_panner_changed ), this, true ) );
}
try
{
- _record_enable_changed_connection =
- dynamic_cast<ARDOUR::Track&>( _route ).rec_enable_control()->Changed
- .connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_record_enable_changed ), this ) )
+ cins = dynamic_cast<ARDOUR::Track&>( _route )
+ .rec_enable_control()
+ ->Changed
+ .connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_record_enable_changed ), this ) )
;
}
catch ( std::bad_cast & )
@@ -59,24 +63,28 @@ void RouteSignal::connect()
// with can't be record-enabled
}
+ // TODO this works when a currently-banked route is made inactive, but not
+ // when a route is activated which should be currently banked.
+ cins = _route.active_changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_active_changed ), this ) );
+
// TODO
- // active_changed
// SelectedChanged
// RemoteControlIDChanged. Better handled at Session level.
}
void RouteSignal::disconnect()
{
- _solo_changed_connection.disconnect();
- _mute_changed_connection.disconnect();
- _gain_changed_connection.disconnect();
- _name_changed_connection.disconnect();
- _panner_changed_connection.disconnect();
- _record_enable_changed_connection.disconnect();
+ for ( Connections::iterator it = _connections.begin(); it != _connections.end(); ++it )
+ {
+ it->disconnect();
+ }
}
void RouteSignal::notify_all()
{
+#ifdef DEBUG
+ cout << "RouteSignal::notify_all for " << _strip << endl;
+#endif
if ( _strip.has_solo() )
_mcp.notify_solo_changed( this );
@@ -93,4 +101,7 @@ void RouteSignal::notify_all()
if ( _strip.has_recenable() )
_mcp.notify_record_enable_changed( this );
+#ifdef DEBUG
+ cout << "RouteSignal::notify_all finish" << endl;
+#endif
}
diff --git a/libs/surfaces/mackie/route_signal.h b/libs/surfaces/mackie/route_signal.h
index 0239980fd4..01b3c97c16 100644
--- a/libs/surfaces/mackie/route_signal.h
+++ b/libs/surfaces/mackie/route_signal.h
@@ -20,6 +20,10 @@
#include <sigc++/sigc++.h>
+#include <vector>
+
+#include "midi_byte_array.h"
+
class MackieControlProtocol;
namespace ARDOUR {
@@ -30,7 +34,7 @@ namespace Mackie
{
class Strip;
-class MackiePort;
+class SurfacePort;
/**
This class is intended to easily create and destroy the set of
@@ -41,8 +45,8 @@ class MackiePort;
class RouteSignal
{
public:
- RouteSignal( ARDOUR::Route & route, MackieControlProtocol & mcp, Strip & strip, MackiePort & port )
- : _route( route ), _mcp( mcp ), _strip( strip ), _port( port )
+ RouteSignal( ARDOUR::Route & route, MackieControlProtocol & mcp, Strip & strip, SurfacePort & port )
+ : _route( route ), _mcp( mcp ), _strip( strip ), _port( port ), _last_gain_written(0.0)
{
connect();
}
@@ -60,20 +64,27 @@ public:
const ARDOUR::Route & route() const { return _route; }
Strip & strip() { return _strip; }
- MackiePort & port() { return _port; }
+ SurfacePort & port() { return _port; }
+
+ float last_gain_written() const { return _last_gain_written; }
+ void last_gain_written( float other ) { _last_gain_written = other; }
+
+ const MidiByteArray & last_pan_written() const { return _last_pan_written; }
+ void last_pan_written( const MidiByteArray & other ) { _last_pan_written = other; }
private:
ARDOUR::Route & _route;
MackieControlProtocol & _mcp;
Strip & _strip;
- MackiePort & _port;
+ SurfacePort & _port;
+
+ typedef std::vector<sigc::connection> Connections;
+ Connections _connections;
- sigc::connection _solo_changed_connection;
- sigc::connection _mute_changed_connection;
- sigc::connection _record_enable_changed_connection;
- sigc::connection _gain_changed_connection;
- sigc::connection _name_changed_connection;
- sigc::connection _panner_changed_connection;
+ // Last written values for the gain and pan, to avoid overloading
+ // the midi connection to the surface
+ float _last_gain_written;
+ MidiByteArray _last_pan_written;
};
}
diff --git a/libs/surfaces/mackie/scripts/bcf-controls.csv b/libs/surfaces/mackie/scripts/bcf-controls.csv
index e22965a906..4dd3bfdd28 100644
--- a/libs/surfaces/mackie/scripts/bcf-controls.csv
+++ b/libs/surfaces/mackie/scripts/bcf-controls.csv
@@ -20,13 +20,13 @@ button,1,assignment,io,1,1,0x28
button,1,assignment,sends,1,1,0x5a
button,1,assignment,pan,1,1,0x59
button,1,assignment,plugin,1,1,0x57
-button,1,assignment,eq,1,1,0x58
-button,1,assignment,dyn,1,1,0x2d
+button,1,functions,drop,1,1,0x58 # was eq
+button,1,assignment,zoom,1,1,0x2d
button,1,bank,left,1,0,0x2e
button,1,bank,right,1,0,0x2f
button,1,bank,channel_left,1,0,0x30
button,1,bank,channel_right,1,0,0x31
-button,1,,flip,1,1,0x32
+button,1,,scrub,1,1,0x32
button,1,,edit,1,1,0x56
button,1,display,name_value,1,0,0x34
@@ -54,12 +54,13 @@ button,1,modifiers,cmd_alt,1,0,0x49
button,1,automation,on,1,1,0x4a
button,1,automation,rec_ready,1,1,0x4b
button,1,functions,undo,1,1,0x4c
-button,1,automation,snapshot,1,1,0x4d
+button,1,automation,snapshot,1,1,0x5f
button,1,functions,redo,1,1,0x4f
button,1,functions,marker,1,1,0x47
button,1,functions,enter,1,1,0x51
button,1,functions,cancel,1,0,0x52
button,1,functions,mixer,1,0,0x53
+button,1,functions,save,1,0,0x4d
# transport buttons
button,1,transport,frm_left,1,1,0x5b
@@ -78,8 +79,8 @@ button,1,cursor,"cursor_up",1,0,0x60
button,1,cursor,"cursor_down",1,0,0x61
button,1,cursor,"cursor_left",1,0,0x62
button,1,cursor,"cursor_right",1,0,0x63
-button,1,,"zoom",1,1,0x64
-button,1,,"scrub",1,1,0x65
+button,1,,"dyn",1,1,0x64
+button,1,,"flip",1,1,0x65
button,1,user,"user_a",1,0,0x66
button,1,user,"user_b",1,0,0x67
diff --git a/libs/surfaces/mackie/scripts/controls.rb b/libs/surfaces/mackie/scripts/controls.rb
index b56fd6010d..666c34d4af 100644
--- a/libs/surfaces/mackie/scripts/controls.rb
+++ b/libs/surfaces/mackie/scripts/controls.rb
@@ -15,8 +15,10 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+this_dir = File.dirname(__FILE__)
+
require 'faster_csv'
-require 'mackie.rb'
+require "#{this_dir}/mackie.rb"
class Control
attr_accessor :id, :led, :group, :name, :ordinal, :switch
@@ -191,6 +193,12 @@ class Surface
end
# add the new control to the various lookups
+ # but first print a warning if the id is duplicated
+ if @controls_by_id.has_key?( row.id ) && control.group.class != Strip
+ duplicated = @controls_by_id[row.id]
+ puts "duplicate id #{control.id}:#{control.name} of #{duplicated.id}:#{duplicated.name}"
+ end
+
@controls_by_id[row.id] = control
@controls << control
group << control
diff --git a/libs/surfaces/mackie/scripts/host.rb b/libs/surfaces/mackie/scripts/host.rb
index 8972cba137..e9ccf695f4 100755
--- a/libs/surfaces/mackie/scripts/host.rb
+++ b/libs/surfaces/mackie/scripts/host.rb
@@ -18,6 +18,11 @@
require 'controls.rb'
require 'mackie.rb'
+if ARGV.size != 2
+ puts "#$0 /dev/snd/midiXXXX control-file.csv"
+ exit 1
+end
+
while !File.exist? ARGV[0]
sleep 0.010
end
@@ -30,46 +35,14 @@ puts ""
file = File.open ARGV[0], 'r+'
mck = Mackie.new( file )
-# send device query
-response = mck.sysex( "\x00" )
-puts "response: #{response.to_hex}"
-
-# decode host connection query
-status = response[0]
-if status != 1
- puts "expected 01, got " + response.to_hex.inspect
- exit(1)
-end
-serial = response[1..7]
-challenge = response[8..11]
-puts <<EOF
-serial: #{serial.to_hex.inspect}
-challenge: #{challenge.to_hex.inspect}
-EOF
-
-# send host connection reply
-response = mck.sysex( "\x02" + serial.pack('C*') + challenge.pack('C*') )
-
-# decode host connection confirmation
-status = response[0]
-if status != 3
- puts "expected 03, got " + response.to_hex.inspect
- exit(1)
-end
-
-serial = response[1..7]
-puts <<EOF
-serial: #{serial.to_hex.inspect}
-EOF
-
# faders to minimum. bcf2000 doesn't respond
-#file.write( hdr + "\x61\xf7" )
+mck.write_sysex "\x61"
# all leds off. bcf2000 doesn't respond
-#file.write( hdr + "\x62\xf7" )
+mck.write_sysex "\x62"
# get version. comes back as ASCII bytes
-version = mck.sysex( "\x13\x00" )
+version = mck.sysex "\x13\x00"
puts "version: #{version.map{|x| x.chr}}"
# write a welcome message. bcf2000 responds with exact
@@ -126,7 +99,7 @@ while bytes = mck.file.read( 3 )
control = sf.midis[midi_type][control_id]
print " Control Type: %-7s, " % sf.types[midi_type]
- print "id: %4i" % control_id
+ print "id: %4x" % control_id
print ", control: %15s" % ( control ? control.name : "nil control" )
print ", %15s" % ( control ? control.group.name : "nil group" )
print "\n"
diff --git a/libs/surfaces/mackie/scripts/mackie-dump.midi b/libs/surfaces/mackie/scripts/mackie-dump.midi
new file mode 100644
index 0000000000..57b36002a5
--- /dev/null
+++ b/libs/surfaces/mackie/scripts/mackie-dump.midi
Binary files differ
diff --git a/libs/surfaces/mackie/scripts/simple_host.rb b/libs/surfaces/mackie/scripts/simple_host.rb
index a5c07f2abb..a369ac8904 100644
--- a/libs/surfaces/mackie/scripts/simple_host.rb
+++ b/libs/surfaces/mackie/scripts/simple_host.rb
@@ -25,17 +25,8 @@ while !File.exist? ARGV[0]
end
file = File.open( ARGV[0], 'r+' )
-mck = Mackie.new( file )
-
-# faders to minimum. bcf2000 doesn't respond
-mck.write_sysex "\x61"
-
-# all leds off. bcf2000 doesn't respond
-mck.write_sysex "\x62"
-
-# get version. comes back as ASCII bytes
-version = mck.sysex "\x13\x00"
-puts "version: #{version.map{|x| x.chr}}"
+#mck = Mackie.new( file )
+device = false
# respond to control movements
while bytes = file.read( 3 )
@@ -121,7 +112,7 @@ while bytes = file.read( 3 )
end
# output bytes
- if output
+ if device && output
#sleep 0.1
puts "sending: %02.x %02.x %02.x" % [ output[0], output[1], output[2] ]
begin
diff --git a/libs/surfaces/mackie/scripts/surface-cc-template.erb b/libs/surfaces/mackie/scripts/surface-cc-template.erb
index 3b29be3249..a82a144b67 100644
--- a/libs/surfaces/mackie/scripts/surface-cc-template.erb
+++ b/libs/surfaces/mackie/scripts/surface-cc-template.erb
@@ -52,17 +52,29 @@ void Mackie::<%= sf.name %>Surface::init_controls()
% end
// initialise controls
- Control * control = 0;
+ Fader * fader = 0;
+ Pot * pot = 0;
+ Button * button = 0;
+ Led * led = 0;
% sf.controls.each do |control|
+ <%-
+ variable_name = control.class.name.downcase
+ class_name =
+ if control.name == 'jog'
+ 'Jog'
+ else
+ control.class.name
+ end
+ -%>
group = groups["<%=control.group.name%>"];
- control = new <%= control.class.name %> ( <%= control.id %>, <%= control.ordinal %>, "<%=control.name%>", *group );
- <%=control.class.name.downcase%>s[0x<%=control.id.to_hex %>] = control;
- controls.push_back( control );
+ <%= variable_name %> = new <%= class_name %> ( <%= control.id %>, <%= control.ordinal %>, "<%=control.name%>", *group );
+ <%= variable_name %>s[0x<%=control.id.to_hex %>] = <%= variable_name %>;
+ controls.push_back( <%= variable_name %> );
<%- if control.group.class != Strip -%>
- controls_by_name["<%= control.name %>"] = control;
+ controls_by_name["<%= control.name %>"] = <%= variable_name %>;
<%- end -%>
- group->add( *control );
+ group->add( *<%= variable_name %> );
% end
}
@@ -82,7 +94,7 @@ void Mackie::<%= sf.name %>Surface::handle_button( MackieButtonHandler & mbh, Bu
buttons = sf.controls.find_all{|x| x.class == Button && x.group.class != Strip}
buttons.each do |button|
%>
- case 0x<%= button.id.to_hex %>: // <%= button.name %>
+ case 0x<%= ( button.class.midi_zero_byte << 8 | button.id ).to_hex %>: // <%= button.name %>
switch ( bs ) {
case press: ls = mbh.<%= button.name %>_press( button ); break;
case release: ls = mbh.<%= button.name %>_release( button ); break;
diff --git a/libs/surfaces/mackie/scripts/test_controls.rb b/libs/surfaces/mackie/scripts/test_controls.rb
index 782b0d427c..5fd34914d8 100755
--- a/libs/surfaces/mackie/scripts/test_controls.rb
+++ b/libs/surfaces/mackie/scripts/test_controls.rb
@@ -4,6 +4,6 @@ require 'controls.rb'
require 'pp'
sf = Surface.new
-sf.parse
+sf.parse( ARGV[0] )
sf.types.each{|k,v| puts "%02.x #{v}" % k}
diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc
index 1110fe117c..e9eb5570ce 100644
--- a/libs/surfaces/mackie/surface.cc
+++ b/libs/surfaces/mackie/surface.cc
@@ -3,7 +3,6 @@
#include <sstream>
#include <iomanip>
#include <iostream>
- #include <typeinfo>
using namespace std;
using namespace Mackie;
@@ -15,8 +14,14 @@ Surface::Surface( uint32_t max_strips, uint32_t unit_strips )
void Surface::init()
{
+#ifdef DEBUG
+ cout << "Surface::init" << endl;
+#endif
init_controls();
init_strips( _max_strips, _unit_strips );
+#ifdef DEBUG
+ cout << "Surface::init finish" << endl;
+#endif
}
Surface::~Surface()
@@ -52,6 +57,8 @@ void Surface::init_strips( uint32_t max_strips, uint32_t unit_strips )
// shallow copy existing strip
// which works because the controls
// have the same ids across units
+ // TODO this needs to be a deep copy because
+ // controls hold state now - in_use
Strip * strip = new Strip( *strips[i % unit_strips] );
// update the relevant values
@@ -64,80 +71,3 @@ void Surface::init_strips( uint32_t max_strips, uint32_t unit_strips )
}
}
}
-
-ostream & Mackie::operator << ( ostream & os, const Mackie::Control & control )
-{
- os << typeid( control ).name();
- os << " { ";
- os << "name: " << control.name();
- os << ", ";
- os << "id: " << "0x" << setw(2) << setfill('0') << hex << control.id() << setfill(' ');
- os << ", ";
- os << "ordinal: " << dec << control.ordinal();
- os << ", ";
- os << "group: " << control.group().name();
- os << " }";
-
- return os;
-}
-
-/**
- TODO could optimise this to use enum, but it's only
- called during the protocol class instantiation.
-
- generated using
-
- irb -r controls.rb
- sf=Surface.new
- sf.parse
- controls = sf.groups.find{|x| x[0] =~ /strip/}.each{|x| puts x[1]}
- controls[1].each {|x| puts "\telse if ( control.name() == \"#{x.name}\" )\n\t{\n\t\t_#{x.name} = reinterpret_cast<#{x.class.name}*>(&control);\n\t}\n"}
-*/
-void Strip::add( Control & control )
-{
- Group::add( control );
- if ( control.name() == "gain" )
- {
- _gain = reinterpret_cast<Fader*>(&control);
- }
- else if ( control.name() == "vpot" )
- {
- _vpot = reinterpret_cast<Pot*>(&control);
- }
- else if ( control.name() == "recenable" )
- {
- _recenable = reinterpret_cast<Button*>(&control);
- }
- else if ( control.name() == "solo" )
- {
- _solo = reinterpret_cast<Button*>(&control);
- }
- else if ( control.name() == "mute" )
- {
- _mute = reinterpret_cast<Button*>(&control);
- }
- else if ( control.name() == "select" )
- {
- _select = reinterpret_cast<Button*>(&control);
- }
- else if ( control.name() == "vselect" )
- {
- _vselect = reinterpret_cast<Button*>(&control);
- }
- else if ( control.name() == "fader_touch" )
- {
- _fader_touch = reinterpret_cast<Button*>(&control);
- }
- else if ( control.type() == Control::type_led || control.type() == Control::type_led_ring )
- {
- // do nothing
- cout << "Strip::add not adding " << control << endl;
- }
- else
- {
- ostringstream os;
- os << "Strip::add: unknown control type " << control;
- throw MackieControlException( os.str() );
- }
-}
-
diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h
index 0ccde75537..5305fe7eb8 100644
--- a/libs/surfaces/mackie/surface.h
+++ b/libs/surfaces/mackie/surface.h
@@ -9,6 +9,8 @@ namespace Mackie
{
class MackieButtonHandler;
+class SurfacePort;
+class MackieMidiBuilder;
/**
This represents an entire control surface, made up of Groups,
@@ -53,11 +55,13 @@ public:
These are alternative addressing schemes
They use maps because the indices aren't always
0-based.
+
+ Indexed by raw_id not by id. @see Control for the distinction.
*/
- std::map<int,Control*> faders;
- std::map<int,Control*> pots;
- std::map<int,Control*> buttons;
- std::map<int,Control*> leds;
+ std::map<int,Fader*> faders;
+ std::map<int,Pot*> pots;
+ std::map<int,Button*> buttons;
+ std::map<int,Led*> leds;
/// no strip controls in here because they usually
/// have the same names.
@@ -79,7 +83,38 @@ public:
/// map button ids to calls to press_ and release_ in mbh
virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button ) = 0;
+
+public:
+ /// display an indicator of the first switched-in Route. Do nothing by default.
+ virtual void display_bank_start( SurfacePort &, MackieMidiBuilder &, uint32_t current_bank ) {};
+
+ /// called from MackieControlPRotocol::zero_all to turn things off
+ virtual void zero_all( SurfacePort &, MackieMidiBuilder & ) {};
+
+ /// turn off leds around the jog wheel. This is for surfaces that use a pot
+ /// pretending to be a jog wheel.
+ virtual void blank_jog_ring( SurfacePort &, MackieMidiBuilder & ) {};
+
+ virtual bool has_timecode_display() const = 0;
+ virtual void display_timecode( SurfacePort &, MackieMidiBuilder &, const std::string & timecode, const std::string & timecode_last ) {};
+public:
+ /**
+ This is used to calculate the clicks per second that define
+ a transport speed of 1.0 for the jog wheel. 100.0 is 10 clicks
+ per second, 50.5 is 5 clicks per second.
+ */
+ virtual float scrub_scaling_factor() = 0;
+
+ /**
+ The scaling factor function for speed increase and decrease. At
+ low transport speeds this should return a small value, for high transport
+ speeds, this should return an exponentially larger value. This provides
+ high definition control at low speeds and quick speed changes to/from
+ higher speeds.
+ */
+ virtual float scaled_delta( const ControlState & state, float current_speed ) = 0;
+
protected:
virtual void init_controls() = 0;
virtual void init_strips( uint32_t max_strips, uint32_t unit_strips );
diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc
index cc5c5cf134..8aaea1d5ba 100644
--- a/libs/surfaces/mackie/surface_port.cc
+++ b/libs/surfaces/mackie/surface_port.cc
@@ -35,18 +35,27 @@
using namespace std;
using namespace Mackie;
+SurfacePort::SurfacePort()
+: _port( 0 ), _number( 0 ), _active( false )
+{
+}
+
SurfacePort::SurfacePort( MIDI::Port & port, int number )
-: _port( port ), _number( number ), _active( false )
+: _port( &port ), _number( number ), _active( false )
{
}
SurfacePort::~SurfacePort()
{
- //cout << "~SurfacePort::SurfacePort()" << endl;
+#ifdef PORT_DEBUG
+ cout << "~SurfacePort::SurfacePort()" << endl;
+#endif
// make sure another thread isn't reading or writing as we close the port
Glib::RecMutex::Lock lock( _rwlock );
_active = false;
- //cout << "~SurfacePort::SurfacePort() finished" << endl;
+#ifdef PORT_DEBUG
+ cout << "~SurfacePort::SurfacePort() finished" << endl;
+#endif
}
// wrapper for one day when strerror_r is working properly
@@ -67,24 +76,29 @@ MidiByteArray SurfacePort::read()
if ( !active() ) return retval;
// return nothing read if the lock isn't acquired
+#if 0
Glib::RecMutex::Lock lock( _rwlock, Glib::TRY_LOCK );
if ( !lock.locked() )
{
- //cout << "SurfacePort::read not locked" << endl;
+ cout << "SurfacePort::read not locked" << endl;
return retval;
}
// check active again - destructor sequence
if ( !active() ) return retval;
+#endif
// read port and copy to return value
- int nread = port().read (buf, sizeof (buf));
+ int nread = port().read( buf, sizeof (buf) );
if (nread >= 0) {
retval.copy( nread, buf );
if ((size_t) nread == sizeof (buf))
{
+#ifdef PORT_DEBUG
+ cout << "SurfacePort::read recursive" << endl;
+#endif
retval << read();
}
}
@@ -101,13 +115,17 @@ MidiByteArray SurfacePort::read()
throw MackieControlException( os.str() );
}
}
+#ifdef PORT_DEBUG
+ cout << "SurfacePort::read: " << retval << endl;
+#endif
return retval;
}
void SurfacePort::write( const MidiByteArray & mba )
{
- //if ( mba[0] == 0xf0 ) cout << "SurfacePort::write: " << mba << endl;
- //cout << "SurfacePort::write: " << mba << endl;
+#ifdef PORT_DEBUG
+ cout << "SurfacePort::write: " << mba << endl;
+#endif
// check active before and after lock - to make sure
// that the destructor doesn't destroy the mutex while
@@ -116,21 +134,26 @@ void SurfacePort::write( const MidiByteArray & mba )
Glib::RecMutex::Lock lock( _rwlock );
if ( !active() ) return;
- int count = port().write( mba.bytes().get(), mba.size(), 0 );
+ int count = port().write( mba.bytes().get(), mba.size(), 0);
if ( count != (int)mba.size() )
{
- if ( errno != EAGAIN )
+ if ( errno == 0 )
+ {
+ cout << "port overflow on " << port().name() << ". Did not write all of " << mba << endl;
+ }
+ else if ( errno != EAGAIN )
{
ostringstream os;
os << "Surface: couldn't write to port " << port().name();
- os << ": " << errno << fetch_errmsg( errno );
+ os << ", error: " << fetch_errmsg( errno ) << "(" << errno << ")";
- cout << os.str();
+ cout << os.str() << endl;
inactive_event();
- throw MackieControlException( os.str() );
}
}
- //if ( mba[0] == 0xf0 ) cout << "SurfacePort::write " << count << endl;
+#ifdef PORT_DEBUG
+ cout << "SurfacePort::wrote " << count << endl;
+#endif
}
void SurfacePort::write_sysex( const MidiByteArray & mba )
@@ -147,22 +170,6 @@ void SurfacePort::write_sysex( MIDI::byte msg )
write( buf );
}
-// This should be moved to midi++ at some point
-ostream & operator << ( ostream & os, const MIDI::Port & port )
-{
- os << "device: " << port.device();
- os << "; ";
- os << "name: " << port.name();
- os << "; ";
- os << "type: " << port.type();
- os << "; ";
- os << "mode: " << port.mode();
- os << "; ";
- os << "ok: " << port.ok();
- os << "; ";
- return os;
-}
-
ostream & Mackie::operator << ( ostream & os, const SurfacePort & port )
{
os << "{ ";
diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h
index 87419f1bcd..421446df68 100644
--- a/libs/surfaces/mackie/surface_port.h
+++ b/libs/surfaces/mackie/surface_port.h
@@ -48,20 +48,20 @@ public:
/// read bytes from the port. They'll either end up in the
/// parser, or if that's not active they'll be returned
- MidiByteArray read();
+ virtual MidiByteArray read();
/// an easier way to output bytes via midi
- void write( const MidiByteArray & );
+ virtual void write( const MidiByteArray & );
/// write a sysex message
void write_sysex( const MidiByteArray & mba );
void write_sysex( MIDI::byte msg );
- // return the correct sysex header for this port
+ /// return the correct sysex header for this port
virtual const MidiByteArray & sysex_hdr() const = 0;
- MIDI::Port & port() { return _port; }
- const MIDI::Port & port() const { return _port; }
+ MIDI::Port & port() { return *_port; }
+ const MIDI::Port & port() const { return *_port; }
// all control notofications are sent from here
sigc::signal<void, SurfacePort &, Control &, const ControlState &> control_event;
@@ -85,8 +85,12 @@ public:
virtual bool active() const { return _active; }
virtual void active( bool yn ) { _active = yn; }
+protected:
+ /// Only for use by DummyPort
+ SurfacePort();
+
private:
- MIDI::Port & _port;
+ MIDI::Port * _port;
int _number;
bool _active;
diff --git a/libs/surfaces/mackie/timer.h b/libs/surfaces/mackie/timer.h
new file mode 100644
index 0000000000..88875539fe
--- /dev/null
+++ b/libs/surfaces/mackie/timer.h
@@ -0,0 +1,136 @@
+/*
+Copyright (C) 1998, 1999, 2000, 2007 John Anderson
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library 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 Library General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef timer_h
+#define timer_h
+
+#ifdef _WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace Mackie
+{
+
+/**
+ millisecond timer class.
+*/
+class Timer
+{
+public:
+
+ /**
+ start the timer running if true, or just create the
+ object if false.
+ */
+ Timer( bool shouldStart = true )
+ {
+ if ( shouldStart )
+ start();
+ }
+
+ /**
+ Start the timer running. Return the current timestamp, in milliseconds
+ */
+ unsigned long start()
+ {
+#ifdef _WIN32
+ _start = (unsigned long)::GetTickCount();
+#else
+ gettimeofday ( &_start, 0 );
+#endif
+ running = true;
+#ifdef _WIN32
+ return _start;
+#else
+ return ( _start.tv_sec * 1000000 + _start.tv_usec ) / 1000;
+#endif
+ }
+
+ /**
+ returns the number of milliseconds since start
+ also stops the timer running
+ */
+ unsigned long stop()
+ {
+#ifdef _WIN32
+ _stop = (unsigned long)::GetTickCount();
+#else
+ gettimeofday ( &_stop, 0 );
+#endif
+ running = false;
+ return elapsed();
+ }
+
+ /**
+ returns the number of milliseconds since start
+ */
+ unsigned long elapsed() const
+ {
+ if ( running )
+ {
+#ifdef _WIN32
+ DWORD current = ::GetTickCount();
+ return current - _start;
+#else
+ struct timeval current;
+ gettimeofday ( &current, 0 );
+ return (
+ ( current.tv_sec * 1000000 + current.tv_usec ) - ( _start.tv_sec * 1000000 + _start.tv_usec )
+ ) / 1000
+ ;
+#endif
+ }
+ else
+ {
+#ifdef _WIN32
+ return _stop - _start;
+#else
+ return (
+ ( _stop.tv_sec * 1000000 + _stop.tv_usec ) - ( _start.tv_sec * 1000000 + _start.tv_usec )
+ ) / 1000
+ ;
+#endif
+ }
+ }
+
+ /**
+ Call stop and then start. Return the value from stop.
+ */
+ unsigned long restart()
+ {
+ unsigned long retval = stop();
+ start();
+ return retval;
+ }
+
+private:
+#ifdef _WIN32
+ unsigned long _start;
+ unsigned long _stop;
+#else
+ struct timeval _start;
+ struct timeval _stop;
+#endif
+ bool running;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/types.cc b/libs/surfaces/mackie/types.cc
index d2818d7340..b9f2e9d488 100644
--- a/libs/surfaces/mackie/types.cc
+++ b/libs/surfaces/mackie/types.cc
@@ -2,8 +2,28 @@
namespace Mackie
{
- LedState on( LedState::on );
- LedState off( LedState::off );
- LedState flashing( LedState::flashing );
- LedState none( LedState::none );
+LedState on( LedState::on );
+LedState off( LedState::off );
+LedState flashing( LedState::flashing );
+LedState none( LedState::none );
+
+std::ostream & operator << ( std::ostream & os, const ControlState & cs )
+{
+ os << "ControlState { ";
+ os << "pos: " << cs.pos;
+ os << ", ";
+ os << "sign: " << cs.sign;
+ os << ", ";
+ os << "delta: " << cs.delta;
+ os << ", ";
+ os << "ticks: " << cs.ticks;
+ os << ", ";
+ os << "led_state: " << cs.led_state.state();
+ os << ", ";
+ os << "button_state: " << cs.button_state;
+ os << " }";
+
+ return os;
+}
+
}
diff --git a/libs/surfaces/mackie/types.h b/libs/surfaces/mackie/types.h
index 2b47e15640..be5c7e8b79 100644
--- a/libs/surfaces/mackie/types.h
+++ b/libs/surfaces/mackie/types.h
@@ -18,6 +18,8 @@
#ifndef mackie_types_h
#define mackie_types_h
+#include <iostream>
+
namespace Mackie
{
@@ -62,23 +64,34 @@ enum ButtonState { neither = -1, release = 0, press = 1 };
*/
struct ControlState
{
- ControlState(): pos(0.0), delta(0.0), button_state(neither) {}
+ ControlState(): pos(0.0), sign(0), delta(0.0), ticks(0), led_state(off), button_state(neither) {}
ControlState( LedState ls ): pos(0.0), delta(0.0), led_state(ls), button_state(neither) {}
// Note that this sets both pos and delta to the flt value
ControlState( LedState ls, float flt ): pos(flt), delta(flt), ticks(0), led_state(ls), button_state(neither) {}
ControlState( float flt ): pos(flt), delta(flt), ticks(0), led_state(none), button_state(neither) {}
- ControlState( float flt, int tcks ): pos(flt), delta(flt), ticks(tcks), led_state(none), button_state(neither) {}
+ ControlState( float flt, unsigned int tcks ): pos(flt), delta(flt), ticks(tcks), led_state(none), button_state(neither) {}
ControlState( ButtonState bs ): pos(0.0), delta(0.0), ticks(0), led_state(none), button_state(bs) {}
+ /// For faders. Between 0 and 1.
float pos;
+
+ /// For pots. Sign. Either -1 or 1;
+ int sign;
+
+ /// For pots. Signed value of total movement. Between 0 and 1
float delta;
- int ticks;
+
+ /// For pots. Unsigned number of ticks. Usually between 1 and 16.
+ unsigned int ticks;
+
LedState led_state;
ButtonState button_state;
};
+std::ostream & operator << ( std::ostream &, const ControlState & );
+
class Control;
class Fader;
class Button;