diff --git a/SConstruct b/SConstruct
index 24a88548e4..160cd1f26e 100644
--- a/SConstruct
+++ b/SConstruct
@@ -311,7 +311,7 @@ env.Append (BUILDERS = {'VersionBuild' : version_bld})
#
def versioned_builder(target,source,env):
- w, r = os.popen2( "svn info | awk '/^Revision:/ { print $2}'")
+ w, r = os.popen2( "LANG= svn info | awk '/^Revision:/ { print $2}'")
last_revision = r.readline().strip()
w.close()
@@ -660,7 +660,8 @@ opt_flags[:0] = [
"-fomit-frame-pointer",
"-ffast-math",
"-fstrength-reduce",
- "-fno-strict-aliasing"
+ "-fno-strict-aliasing",
+ "-pipe"
]
if env['DEBUG'] == 1:
@@ -950,7 +951,7 @@ else:
# its included in the tarball
#
-surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi', 'libs/surfaces/tranzport' ]
+surface_subdirs = [ 'libs/surfaces/control_protocol', 'libs/surfaces/generic_midi', 'libs/surfaces/tranzport', 'libs/surfaces/mackie' ]
if env['SURFACES']:
if have_libusb:
@@ -1061,6 +1062,13 @@ if not conf.CheckFunc('posix_memalign'):
env = conf.Finish()
rcbuild = env.SubstInFile ('ardour.rc','ardour.rc.in', SUBST_DICT = subst_dict)
+subst_dict['%VERSION%'] = ardour_version[0:3]
+subst_dict['%EXTRA_VERSION%'] = ardour_version[3:]
+subst_dict['%REVISION_STRING%'] = ''
+if os.path.exists('.svn'):
+ subst_dict['%REVISION_STRING%'] = '.' + fetch_svn_revision ('.') + 'svn'
+
+specbuild = env.SubstInFile ('ardour.spec','ardour.spec.in', SUBST_DICT = subst_dict)
the_revision = env.Command ('frobnicatory_decoy', [], create_stored_revision)
@@ -1078,6 +1086,7 @@ env.Distribute (env['DISTTREE'],
[ 'SConstruct', 'svn_revision.h',
'COPYING', 'PACKAGER_README', 'README',
'ardour.rc.in',
+ 'ardour.spec',
'ardour_system.rc',
'tools/config.guess',
'icons/icon/ardour_icon_mac_mask.png',
diff --git a/libs/ardour/ardour/configuration_vars.h b/libs/ardour/ardour/configuration_vars.h
index 9e69114d9f..a779c77df7 100644
--- a/libs/ardour/ardour/configuration_vars.h
+++ b/libs/ardour/ardour/configuration_vars.h
@@ -23,6 +23,7 @@ CONFIG_VARIABLE (bool, midi_control, "midi-control", false)
CONFIG_VARIABLE (uint32_t, feedback_interval_ms, "feedback-interval-ms", 100)
CONFIG_VARIABLE (bool, use_tranzport, "use-tranzport", false)
+CONFIG_VARIABLE (std::string, mackie_emulation, "mackie-emulation", "mcu")
/* disk operations */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 66c2bc4fee..cfc2635146 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -333,7 +333,7 @@ class Session : public PBD::StatefulDestructible
/* Record status signals */
- sigc::signal RecordStateChanged;
+ sigc::signal RecordStateChanged;
/* Transport mechanism signals */
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 3e10df9dba..0134a0ac1c 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -738,7 +738,7 @@ Region::state (bool full_state)
{
XMLNode *node = new XMLNode ("Region");
char buf[64];
- char* fe;
+ char* fe = NULL;
_id.print (buf, sizeof (buf));
node->add_property ("id", buf);
@@ -760,6 +760,10 @@ Region::state (bool full_state)
case EditChangesID:
fe = X_("id");
break;
+ default: /* should be unreachable but makes g++ happy */
+ cerr << "Odd region property found\n";
+ fe = X_("nothing");
+ break;
}
node->add_property ("first_edit", fe);
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 4a896d80ac..d3063ba634 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -3407,11 +3407,11 @@ Session::available_capture_duration ()
switch (Config->get_native_file_data_format()) {
case FormatFloat:
- sample_bytes_on_disk = 4;
+ sample_bytes_on_disk = 4.0;
break;
case FormatInt24:
- sample_bytes_on_disk = 3;
+ sample_bytes_on_disk = 3.0;
break;
default:
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index 1ecf4fce8d..91e3fb436f 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -404,6 +404,7 @@ Session::GlobalMeteringStateCommand::get_state()
case MeterPostFader:
meterstr = X_("post");
break;
+ default: meterstr = "";
}
child->add_property (X_("meter"), meterstr);
@@ -430,6 +431,7 @@ Session::GlobalMeteringStateCommand::get_state()
case MeterPostFader:
meterstr = X_("post");
break;
+ default: meterstr = "";
}
child->add_property (X_("meter"), meterstr);
diff --git a/libs/surfaces/frontier/kernel_drivers/BUILD b/libs/surfaces/frontier/kernel_drivers/BUILD
new file mode 100644
index 0000000000..dc612e20bf
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/BUILD
@@ -0,0 +1,10 @@
+To build, type make
+
+# make install and run
+ir: install
+ rmmod tranzport
+ modprobe tranzport
+
+# make install, run, and run tests
+irt: ir
+
diff --git a/libs/surfaces/frontier/kernel_drivers/Makefile b/libs/surfaces/frontier/kernel_drivers/Makefile
new file mode 100644
index 0000000000..223fcdb6fc
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/Makefile
@@ -0,0 +1,35 @@
+ifneq ($(KERNELRELEASE),)
+
+obj-m := tranzport.o
+tranzport-objs :=
+
+else
+
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+MODDIR := $(DESTDIR)/lib/modules/$(shell uname -r)/kernel/sound/usb/misc
+BINDIR := $(DESTDIR)/usr/local/bin
+
+default::
+ $(MAKE) -Wall -C $(KDIR) SUBDIRS=$(PWD) modules
+ $(MAKE) -C tests
+
+install-only:: default
+ mkdir -p $(MODDIR) $(BINDIR)
+ cp tranzport.ko $(MODDIR)
+ $(MAKE) -C tests install
+
+install:: install-only
+ /sbin/depmod -a
+ +/sbin/rmmod tranzport
+ /sbin/modprobe tranzport
+
+irt:: install
+ tranzport_tests.sh
+
+clean::
+ rm -f core .*.cmd *.o *.ko *.mod.c Module.symvers *.bak .\#* *~
+ rm -rf .tmp_versions
+ $(MAKE) -C tests clean
+
+endif
diff --git a/libs/surfaces/frontier/kernel_drivers/README b/libs/surfaces/frontier/kernel_drivers/README
new file mode 100644
index 0000000000..51b4af0f2e
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/README
@@ -0,0 +1,16 @@
+This directory contains the USB Tranzport Kernel driver for Linux.
+
+At present it accepts reads/writes of 8 byte cmds to /dev/tranzport0 to control
+the lights and screen.
+
+Reads are possible. Wheel Compression does not currently account for button changes
+
+It also has some sysfs hooks that are non-functional at the moment.
+
+The API is closely tied to the ardour revision and WILL change.
+
+A sysfs interface is PERFECT for simple userspace apps to do fun things with the
+lights and screen. It's fairly lousy for handling input events and very lousy
+for watching the state of the shuttle wheel.
+
+In the end this is going to be driven by a midi layer
diff --git a/libs/surfaces/frontier/kernel_drivers/doc/keycodes.html b/libs/surfaces/frontier/kernel_drivers/doc/keycodes.html
new file mode 100644
index 0000000000..651517a7f2
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/doc/keycodes.html
@@ -0,0 +1,35 @@
+
+
+ TRANZPORT KEYCODES REFERENCE
+
+
+
TRANZPORT KEYCODES REFERENCE
+
+
Footswitch
+
+At least on every footswitch I've tried, the polarity appears to be wrong, in that the footswitch "up" position results
+in 0100 being OR'd into the result. Pressing it down results in a 0, if no other keys are pressed. Releasing it results in 0100.
+
+Every other key when up results in 0. This odd behavior would hopefully be controllable via a command to the tranzport,
+but I don't have that, so dealing with footswitch events is weird.
+
+So, seeing this bit enabled would be something like "HAVE_FOOTSWITCH INSTALLED", BE SMART ABOUT IT.
+
+
+
Special Key Combinations
+
+In addition to the normal keycodes generated by the tranzport, it is possible to hit several combinations of keys and get a unique
+result. Some are really weird. Perhaps the following assignments make sense:
+
+
PRESSING
RESULT
ASSIGNED TO
+
TRACKLEFT+TRACKRIGHT
TRACKLEFT+TRACKRIGHT
Master
+
SHIFT+TRACKLEFT+TRACKRIGHT
SHIFT+TRACKLEFT+TRACKRIGHT+UNDO
Show Bus Only Toggle
+
IN+OUT
IN+OUT
Zoom 100%
+
SHIFT+IN+OUT
SHIFT+IN+OUT+UNDO
Max Zoom
+
SHIFT+REW+FFW
SHIFT+REW+FFW+UNDO
+
RECORD+TRACKSOLO+FOOTSWITCHNOTDEPRESSED
RECORD+TRACKSOLO+BATTERY
+
PLAY+MUTE
PLAY+MUTE
+
+
+
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/Makefile b/libs/surfaces/frontier/kernel_drivers/tests/Makefile
new file mode 100644
index 0000000000..534bc7da4b
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/Makefile
@@ -0,0 +1,23 @@
+# Some basic utilities for testing the tranzport's I/O
+# eventually "tranzport" will become a flexible command
+#
+#
+
+FILES:=tranzport tranzport_lights tranzport_tests.sh
+BINDIR ?= $(DESTDIR)/usr/local/bin
+
+all: tranzport tranzport_lights
+
+tranzport: tranzport.c
+ gcc -g -Wall -o tranzport tranzport.c
+
+tranzport_lights: tranzport_lights.c
+ gcc -g -Wall -o tranzport_lights tranzport_lights.c
+
+clean::
+ rm -f core .*.cmd *.o *.ko *.mod.c Module.symvers *.bak .\#* *~
+ rm -rf .tmp_versions tranzport tranzport_lights
+
+install::
+ cp $(FILES) $(BINDIR)
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/README b/libs/surfaces/frontier/kernel_drivers/tests/README
new file mode 100644
index 0000000000..f9efd18f69
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/README
@@ -0,0 +1,104 @@
+tranzport 0.1
+oct 18, 2005
+arthur@artcmusic.com
+---
+
+The Frontier Design Tranzport(tm) (www.frontierdesign.com) is a simple
+wireless USB device. It is not a MIDI device. The document on their web
+site "Tranzport(tm) Native Mode Interface Description" describes the
+Tranzport(tm) as if it were a MIDI device, but this is implemented by their
+Windows and Macintosh software drivers.
+
+This code will allow you to use your Tranzport(tm) at a lower level of
+abstraction. This code relies on libusb, which can be obtained from
+libusb.sourceforge.net.
+
+To compile the program, type "make". You should end up with a executable
+called "tranzport". You'll probably have to run this program as root.
+
+Using the program is straightforward. It will simply tell you which
+buttons are being pressed and what not. If you press one of the buttons
+with a light, the light will turn on. If you hold shift and press one of
+the buttons with a light, the light will turn off. If you take out the
+batteries to the device (or go out of range), it will tell you that the
+device is offline. When you replace the batteries (or come back in
+range), it should tell you it is back online.
+
+Once you understand how everything works, you should be able to
+incorporate it into your own setup however you wish.
+
+This code was developed on a Linux machine, but (theoretically) it
+should work on any system that is supported by libusb, since that is how
+it communicates with the device.
+
+Here are a few more details about the device:
+
+There are two endpoints for communication with the device. All data
+reads and writes are done in 8-byte segments.
+
+One endpoint is for interrupt reads. This is used to read button data
+from the device. It also supplies status information for when the device
+goes out of range and comes back in range, loses power and regains
+power, etc. The format of the data is:
+
+ 00 ss bb bb bb bb dd 00 (hexadecimal)
+
+where:
+
+ ss - status code, 01=online ff=offline
+ bb - button bits
+ dd - data wheel, 01-3f=forward 41-7f=backward
+
+Please refer to the source code for a list of the button bits.
+
+The other endpoint is for interrupt writes. This is used to toggle the
+lights on the device, and to write data to the LCD.
+
+There are 7 lights on the device. To turn a light on, send the following
+sequence of bytes:
+
+ 00 00 nn 01 00 00 00 00 (hexadecimal)
+
+where nn is the light number.
+
+To turn a light off:
+
+ 00 00 nn 00 00 00 00 00 (hexadecimal)
+
+Here is the list of lights:
+
+ 00 Record
+ 01 Track Rec
+ 02 Track Mute
+ 03 Track Solo
+ 04 Any Solo
+ 05 Loop
+ 06 Punch
+
+The size of the LCD is 20x2, and it is split into 10 cells, each cell
+being 4 characters wide. The cells progress across, then down. To write
+to the LCD, send the following sequence of bytes:
+
+ 00 01 cc aa aa aa aa 00 (hexadecimal)
+
+where:
+
+ cc - cell number
+ aa - ASCII code
+
+Here is a list of the cells to clarify:
+
+ 00 row 0, column 0-3
+ 01 row 0, column 4-7
+ 02 row 0, column 8-11
+ 03 row 0, column 12-15
+ 04 row 0, column 16-19
+ 05 row 1, column 0-3
+ 06 row 1, column 4-7
+ 07 row 1, column 8-11
+ 08 row 1, column 12-15
+ 09 row 1, column 16-19
+
+You should refer to the "Tranzport(tm) Native Mode Interface
+Description" document for a listing of the ASCII codes the LCD uses.
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/tranzport.c b/libs/surfaces/frontier/kernel_drivers/tests/tranzport.c
new file mode 100644
index 0000000000..2ef5b6c910
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/tranzport.c
@@ -0,0 +1,375 @@
+/*
+ * tranzport 0.1
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+#define STATUS_OK 0x00
+
+struct tranzport_s {
+ int *dev;
+ int udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core()
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->udev = open("/dev/tranzport0",O_RDWR);
+ if (z->udev < 1)
+ die("unable to open tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+return open_tranzport_core();
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = close(z->udev);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = write(z->udev, cmd, 8);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0xff, 8);
+ val = read(z->udev, buf, 8);
+ if (val < 0) {
+ printf("errno: %d\n",errno);
+ switch(errno) {
+ case ENOENT: ;
+ case ECONNRESET: ;
+ case ESHUTDOWN: printf("dying\n"); exit(1); break;
+ }
+ return val;
+ }
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 10);
+ } else {
+ tranzport_lighton(z, light, 10);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons: %x ", buttons);
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 10);
+ tranzport_lcdwrite(z, 1, "DISL", 10);
+ tranzport_lcdwrite(z, 2, "EXIA", 10);
+ tranzport_lcdwrite(z, 3, " FOR", 10);
+ tranzport_lcdwrite(z, 4, " ", 10);
+
+ tranzport_lcdwrite(z, 5, " ", 10);
+ tranzport_lcdwrite(z, 6, " CUR", 10);
+ tranzport_lcdwrite(z, 7, "E FO", 10);
+ tranzport_lcdwrite(z, 8, "UND ", 10);
+ tranzport_lcdwrite(z, 9, " ", 10);
+}
+
+void do_lcd2(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, "THE ", 10);
+ tranzport_lcdwrite(z, 1, "TRAN", 10);
+ tranzport_lcdwrite(z, 2, "ZPOR", 10);
+ tranzport_lcdwrite(z, 3, "T RO", 10);
+ tranzport_lcdwrite(z, 4, " KS", 10);
+
+ tranzport_lcdwrite(z, 5, "AWES", 10);
+ tranzport_lcdwrite(z, 6, "OMEE", 10);
+ tranzport_lcdwrite(z, 7, "LEEE", 10);
+ tranzport_lcdwrite(z, 8, "UND ", 10);
+ tranzport_lcdwrite(z, 9, "GROK", 10);
+}
+
+int lights_off(tranzport_t *z) {
+ static int i = 0;
+ int j = 0;
+ for(;j<2; j++,i = (i+1) % 7) {
+ tranzport_lightoff(z, i, 10);
+ }
+return 0;
+}
+
+int lights_on(tranzport_t *z) {
+ static int i = 0;
+ int j = 0;
+ for(;j<2; j++,i = (i+1) % 7) {
+ tranzport_lighton(z, i, 10);
+ }
+return 0;
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+
+ // do_lcd(z);
+ lights_on(z);
+ // do_lcd2(z);
+
+ val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline: ");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online: ");
+ do_lcd(z);
+ }
+
+ if (status == STATUS_OK) {
+ printf("OK: ");
+ do_lcd(z);
+ }
+
+// do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ lights_off(z);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c
new file mode 100644
index 0000000000..4096ee680d
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_lights.c
@@ -0,0 +1,361 @@
+/*
+ * tranzport 0.1
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+#define STATUS_OK 0x00
+
+struct tranzport_s {
+ int *dev;
+ int udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core()
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->udev = open("/dev/tranzport0",O_RDWR);
+ if (!z->udev)
+ die("unable to open tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+return open_tranzport_core();
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = close(z->udev);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = write(z->udev, cmd, 8);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0xff, 8);
+ val = read(z->udev, buf, 8);
+ if (val < 0) {
+ // printf("errno: %d\n",errno);
+ return val;
+ }
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 1000);
+ } else {
+ tranzport_lighton(z, light, 1000);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons: %x ", buttons);
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 1000);
+ tranzport_lcdwrite(z, 1, "DISL", 1000);
+ tranzport_lcdwrite(z, 2, "EXIA", 1000);
+ tranzport_lcdwrite(z, 3, " FOR", 1000);
+ tranzport_lcdwrite(z, 4, " ", 1000);
+
+ tranzport_lcdwrite(z, 5, " ", 1000);
+ tranzport_lcdwrite(z, 6, " CUR", 1000);
+ tranzport_lcdwrite(z, 7, "E FO", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, " ", 1000);
+}
+
+void do_lcd2(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, "THE ", 1000);
+ tranzport_lcdwrite(z, 1, "TRAN", 1000);
+ tranzport_lcdwrite(z, 2, "ZPOR", 1000);
+ tranzport_lcdwrite(z, 3, "T RO", 1000);
+ tranzport_lcdwrite(z, 4, "KS ", 1000);
+
+ tranzport_lcdwrite(z, 5, "AWES", 1000);
+ tranzport_lcdwrite(z, 6, "OMEE", 1000);
+ tranzport_lcdwrite(z, 7, "LEEE", 1000);
+ tranzport_lcdwrite(z, 8, "WITH", 1000);
+ tranzport_lcdwrite(z, 9, "ARDO", 1000);
+}
+
+lights_off(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lightoff(z, i, 1000);
+ }
+}
+
+lights_on(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lighton(z, i, 1000);
+ }
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+
+ do_lcd(z);
+ lights_on(z);
+ do_lcd2(z);
+ lights_off(z);
+
+// val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ val = -1;
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline: ");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online: ");
+ do_lcd(z);
+ }
+
+ do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh
new file mode 100755
index 0000000000..540c62fe16
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tests/tranzport_tests.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+echo "Testing lights"
+tranzport_lights &
+A=$!
+sleep 30
+kill $A
+echo "Testing interleaved_reads/writes"
+tranzport &
+A=$!
+sleep 30
+kill $A
+
+exit 0
+
+# not done yet
+echo "Testing_screen"
+tranzport_screen &
+A=$!
+sleep 30
+kill $A
+echo "Testing_reads"
+tranzport_read &
+A=$!
+sleep 30
+kill $A
+
diff --git a/libs/surfaces/frontier/kernel_drivers/tranzport.c b/libs/surfaces/frontier/kernel_drivers/tranzport.c
new file mode 100644
index 0000000000..6893f66921
--- /dev/null
+++ b/libs/surfaces/frontier/kernel_drivers/tranzport.c
@@ -0,0 +1,1065 @@
+/*
+ * Frontier Designs Tranzport driver
+ *
+ * Copyright (C) 2007 Michael Taht (m@taht.net)
+ *
+ * Based on the usbled driver and ldusb drivers by
+ *
+ * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2005 Michael Hund
+ *
+ * The ldusb driver was, in turn, derived from Lego USB Tower driver
+ * Copyright (C) 2003 David Glance
+ * 2001-2004 Juergen Stuber
+ *
+ * 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, version 2.
+ *
+ */
+
+/**
+ * This driver uses a ring buffer for time critical reading of
+ * interrupt in reports and provides read and write methods for
+ * raw interrupt reports.
+ */
+
+/* Note: this currently uses a dumb ringbuffer for reads and writes.
+ * A more optimal driver would cache and kill off outstanding urbs that are
+ * now invalid, and ignore ones that already were in the queue but valid
+ * as we only have 17 commands for the tranzport. In particular this is
+ * key for getting lights to flash in time as otherwise many commands
+ * can be buffered up before the light change makes it to the interface.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+/* Define these values to match your devices */
+#define VENDOR_ID 0x165b
+#define PRODUCT_ID 0x8101
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define USB_TRANZPORT_MINOR_BASE 0
+#else
+// FIXME 176 - is the ldusb driver's minor - apply for that
+#define USB_TRANZPORT_MINOR_BASE 176
+#endif
+
+/* table of devices that work with this driver */
+static struct usb_device_id usb_tranzport_table [] = {
+ { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usb_tranzport_table);
+MODULE_VERSION("0.29");
+MODULE_AUTHOR("Mike Taht ");
+MODULE_DESCRIPTION("Tranzport USB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("Frontier Designs Control Surface");
+
+
+/* make this work on older kernel versions */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+
+/**
+ * usb_endpoint_dir_out - check if the endpoint has OUT direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type OUT, otherwise it returns false.
+ */
+
+static inline int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+}
+
+static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
+}
+
+
+/**
+ * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type interrupt, otherwise it returns
+ * false.
+ */
+static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT);
+}
+
+
+/**
+ * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and IN direction,
+ * otherwise it returns false.
+ */
+
+static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+
+static inline int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
+}
+
+#endif /* older kernel versions */
+
+/* These two aren't done yet */
+
+#define SUPPRESS_EXTRA_ONLINE_EVENTS 0
+#define BUFFERED_WRITES 0
+
+#define SUPPRESS_EXTRA_OFFLINE_EVENTS 1
+#define COMPRESS_WHEEL_EVENTS 1
+#define BUFFERED_READS 1
+#define RING_BUFFER_SIZE 1000
+#define WRITE_BUFFER_SIZE 34
+#define TRANZPORT_USB_TIMEOUT 10
+
+
+static int debug = 0;
+
+/* Use our own dbg macro */
+#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+/* Module parameters */
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* All interrupt in transfers are collected in a ring buffer to
+ * avoid racing conditions and get better performance of the driver.
+ */
+
+static int ring_buffer_size = RING_BUFFER_SIZE;
+
+module_param(ring_buffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports");
+
+/* The write_buffer can one day contain more than one interrupt out transfer.
+ */
+static int write_buffer_size = WRITE_BUFFER_SIZE;
+module_param(write_buffer_size, int, S_IRUGO);
+MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
+
+/*
+ * Increase the interval for debugging purposes.
+ * or set to 1 to use the standard interval from the endpoint descriptors.
+ */
+
+static int min_interrupt_in_interval = TRANZPORT_USB_TIMEOUT;
+module_param(min_interrupt_in_interval, int, 0);
+MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms");
+
+static int min_interrupt_out_interval = TRANZPORT_USB_TIMEOUT;
+module_param(min_interrupt_out_interval, int, 0);
+MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms");
+
+struct tranzport_cmd {
+ unsigned char cmd[8];
+};
+
+/* Structure to hold all of our device specific stuff */
+struct usb_tranzport {
+ struct semaphore sem; /* locks this structure */
+ struct usb_interface* intf; /* save off the usb interface pointer */
+
+ int open_count; /* number of times this port has been opened */
+
+ struct tranzport_cmd (*ring_buffer)[RING_BUFFER_SIZE]; /* just make c happy */
+ unsigned int ring_head;
+ unsigned int ring_tail;
+
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ unsigned char* interrupt_in_buffer;
+ struct usb_endpoint_descriptor* interrupt_in_endpoint;
+ struct urb* interrupt_in_urb;
+ int interrupt_in_interval;
+ size_t interrupt_in_endpoint_size;
+ int interrupt_in_running;
+ int interrupt_in_done;
+
+ char* interrupt_out_buffer;
+ struct usb_endpoint_descriptor* interrupt_out_endpoint;
+ struct urb* interrupt_out_urb;
+ int interrupt_out_interval;
+ size_t interrupt_out_endpoint_size;
+ int interrupt_out_busy;
+
+ /* Sysfs support - most of these are not hooked up yet */
+
+ int event; /* alternate interface to events */
+ int wheel; /* - for negative, 0 for none, + for positive */
+ int lights;
+ unsigned char dump_state; /* 0 if disabled 1 if enabled */
+ unsigned char enable; /* 0 if disabled 1 if enabled */
+ unsigned char offline; /* if the device is out of range or asleep */
+ unsigned char compress_wheel; /* flag to compress wheel events */
+ unsigned char LightRecord;
+ unsigned char LightTrackrec;
+ unsigned char LightTrackmute;
+ unsigned char LightTracksolo;
+ unsigned char LightAnysolo;
+ unsigned char LightLoop;
+ unsigned char LightPunch;
+ unsigned char last_cmd[8];
+ unsigned char screen[40]; // We'll also have cells
+
+};
+
+/* prevent races between open() and disconnect() */
+static DEFINE_MUTEX(disconnect_mutex);
+
+static struct usb_driver usb_tranzport_driver;
+
+/**
+ * usb_tranzport_abort_transfers
+ * aborts transfers and frees associated data structures
+ */
+static void usb_tranzport_abort_transfers(struct usb_tranzport *dev)
+{
+ /* shutdown transfer */
+ if (dev->interrupt_in_running) {
+ dev->interrupt_in_running = 0;
+ if (dev->intf)
+ usb_kill_urb(dev->interrupt_in_urb);
+ }
+ if (dev->interrupt_out_busy)
+ if (dev->intf)
+ usb_kill_urb(dev->interrupt_out_urb);
+}
+
+#define show_set_light(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", t->value); \
+} \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ int temp = simple_strtoul(buf, NULL, 10); \
+ \
+ t->value = temp; \
+ return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+
+show_set_light(LightRecord);
+show_set_light(LightTrackrec);
+show_set_light(LightTrackmute);
+show_set_light(LightTracksolo);
+show_set_light(LightAnysolo);
+show_set_light(LightLoop);
+show_set_light(LightPunch);
+
+show_set_light(enable);
+show_set_light(offline);
+show_set_light(compress_wheel);
+show_set_light(dump_state);
+
+#define show_set_int(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", t->value); \
+} \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ int temp = simple_strtoul(buf, NULL, 10); \
+ \
+ t->value = temp; \
+ return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+
+show_set_int(wheel);
+show_set_int(event);
+
+#define show_set_cmd(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ \
+ return sprintf(buf, "%d\n", t->value); \
+} \
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct usb_interface *intf = to_usb_interface(dev); \
+ struct usb_tranzport *t = usb_get_intfdata(intf); \
+ int temp = simple_strtoul(buf, NULL, 10); \
+ \
+ t->value = temp; \
+ return count; \
+} \
+static DEVICE_ATTR(value, S_IWUGO | S_IRUGO, show_##value, set_##value);
+
+
+
+
+/**
+ * usb_tranzport_delete
+ */
+static void usb_tranzport_delete(struct usb_tranzport *dev)
+{
+ usb_tranzport_abort_transfers(dev);
+ /* This is just too twisted to be correct */
+ if(dev->intf != NULL) {
+ device_remove_file(&dev->intf->dev, &dev_attr_LightRecord);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTrackrec);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTrackmute);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTracksolo);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightTrackmute);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightAnysolo);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightLoop);
+ device_remove_file(&dev->intf->dev, &dev_attr_LightPunch);
+ device_remove_file(&dev->intf->dev, &dev_attr_wheel);
+ device_remove_file(&dev->intf->dev, &dev_attr_enable);
+ device_remove_file(&dev->intf->dev, &dev_attr_event);
+ device_remove_file(&dev->intf->dev, &dev_attr_offline);
+ device_remove_file(&dev->intf->dev, &dev_attr_compress_wheel);
+
+ device_remove_file(&dev->intf->dev, &dev_attr_dump_state);
+ }
+
+ /* free data structures */
+ usb_free_urb(dev->interrupt_in_urb);
+ usb_free_urb(dev->interrupt_out_urb);
+ kfree(dev->ring_buffer);
+ kfree(dev->interrupt_in_buffer);
+ kfree(dev->interrupt_out_buffer);
+ kfree(dev);
+}
+
+/**
+ * usb_tranzport_interrupt_in_callback
+ */
+
+static void usb_tranzport_interrupt_in_callback(struct urb *urb)
+{
+ struct usb_tranzport *dev = urb->context;
+ unsigned int next_ring_head;
+ int retval = -1;
+
+ if (urb->status) {
+ if (urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN) {
+ goto exit;
+ } else {
+ dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
+ __FUNCTION__, urb->status);
+ goto resubmit; /* maybe we can recover */
+ }
+ }
+
+ if (urb->actual_length != 8) {
+ dev_warn(&dev->intf->dev,
+ "Urb length was %d bytes!! Do something intelligent \n", urb->actual_length);
+ } else {
+ dbg_info(&dev->intf->dev, "%s: received: %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __FUNCTION__, dev->interrupt_in_buffer[0],dev->interrupt_in_buffer[1],dev->interrupt_in_buffer[2],dev->interrupt_in_buffer[3],dev->interrupt_in_buffer[4],dev->interrupt_in_buffer[5],dev->interrupt_in_buffer[6],dev->interrupt_in_buffer[7]);
+#if SUPPRESS_EXTRA_OFFLINE_EVENTS
+ if(dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) { goto resubmit; }
+ if(dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; }
+
+/* Always pass one offline event up the stack */
+ if(dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) { dev->offline = 0; }
+ if(dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 1; }
+
+#endif
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+
+ next_ring_head = (dev->ring_head+1) % ring_buffer_size;
+
+ if (next_ring_head != dev->ring_tail) {
+ memcpy(&((*dev->ring_buffer)[dev->ring_head]), dev->interrupt_in_buffer, urb->actual_length);
+ dev->ring_head = next_ring_head;
+ retval = 0;
+ memset(dev->interrupt_in_buffer, 0, urb->actual_length);
+ } else {
+ dev_warn(&dev->intf->dev,
+ "Ring buffer overflow, %d bytes dropped\n",
+ urb->actual_length);
+ memset(dev->interrupt_in_buffer, 0, urb->actual_length);
+ }
+ }
+
+resubmit:
+ /* resubmit if we're still running */
+ if (dev->interrupt_in_running && dev->intf) {
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&dev->intf->dev,
+ "usb_submit_urb failed (%d)\n", retval);
+ }
+
+exit:
+ dev->interrupt_in_done = 1;
+ wake_up_interruptible(&dev->read_wait);
+}
+
+/**
+ * usb_tranzport_interrupt_out_callback
+ */
+static void usb_tranzport_interrupt_out_callback(struct urb *urb)
+{
+ struct usb_tranzport *dev = urb->context;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status && !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ dbg_info(&dev->intf->dev,
+ "%s - nonzero write interrupt status received: %d\n",
+ __FUNCTION__, urb->status);
+
+ dev->interrupt_out_busy = 0;
+ wake_up_interruptible(&dev->write_wait);
+}
+
+/**
+ * usb_tranzport_open
+ */
+static int usb_tranzport_open(struct inode *inode, struct file *file)
+{
+ struct usb_tranzport *dev;
+ int subminor;
+ int retval = 0;
+ struct usb_interface *interface;
+
+ nonseekable_open(inode, file);
+ subminor = iminor(inode);
+
+ mutex_lock(&disconnect_mutex);
+
+ interface = usb_find_interface(&usb_tranzport_driver, subminor);
+
+ if (!interface) {
+ err("%s - error, can't find device for minor %d\n",
+ __FUNCTION__, subminor);
+ retval = -ENODEV;
+ goto unlock_disconnect_exit;
+ }
+
+ dev = usb_get_intfdata(interface);
+
+ if (!dev) {
+ retval = -ENODEV;
+ goto unlock_disconnect_exit;
+ }
+
+ /* lock this device */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto unlock_disconnect_exit;
+ }
+
+ /* allow opening only once */
+ if (dev->open_count) {
+ retval = -EBUSY;
+ goto unlock_exit;
+ }
+ dev->open_count = 1;
+
+ /* initialize in direction */
+ dev->ring_head = 0;
+ dev->ring_tail = 0;
+ usb_fill_int_urb(dev->interrupt_in_urb,
+ interface_to_usbdev(interface),
+ usb_rcvintpipe(interface_to_usbdev(interface),
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ dev->interrupt_in_endpoint_size,
+ usb_tranzport_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_interval);
+
+ dev->interrupt_in_running = 1;
+ dev->interrupt_in_done = 0;
+ dev->enable = 1;
+ dev->offline = 0;
+ dev->compress_wheel = 1;
+
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval);
+ dev->interrupt_in_running = 0;
+ dev->open_count = 0;
+ goto unlock_exit;
+ }
+
+ /* save device in the file's private structure */
+ file->private_data = dev;
+
+
+unlock_exit:
+ up(&dev->sem);
+
+unlock_disconnect_exit:
+ mutex_unlock(&disconnect_mutex);
+
+ return retval;
+}
+
+/**
+ * usb_tranzport_release
+ */
+static int usb_tranzport_release(struct inode *inode, struct file *file)
+{
+ struct usb_tranzport *dev;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ if (dev == NULL) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ if (dev->open_count != 1) {
+ retval = -ENODEV;
+ goto unlock_exit;
+ }
+
+ if (dev->intf == NULL) {
+ /* the device was unplugged before the file was released */
+ up(&dev->sem);
+ /* unlock here as usb_tranzport_delete frees dev */
+ usb_tranzport_delete(dev);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* wait until write transfer is finished */
+ if (dev->interrupt_out_busy)
+ wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
+ usb_tranzport_abort_transfers(dev);
+ dev->open_count = 0;
+
+unlock_exit:
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/**
+ * usb_tranzport_poll
+ */
+static unsigned int usb_tranzport_poll(struct file *file, poll_table *wait)
+{
+ struct usb_tranzport *dev;
+ unsigned int mask = 0;
+
+ dev = file->private_data;
+
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+ if (dev->ring_head != dev->ring_tail)
+ mask |= POLLIN | POLLRDNORM;
+ if (!dev->interrupt_out_busy)
+ mask |= POLLOUT | POLLWRNORM;
+
+ return mask;
+}
+
+/**
+ * usb_tranzport_read
+ */
+static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct usb_tranzport *dev;
+ size_t bytes_to_read;
+ int retval = 0;
+
+#if BUFFERED_READS
+ int c = 0;
+#endif
+
+#if COMPRESS_WHEEL_EVENTS
+ signed char oldwheel;
+ signed char newwheel;
+ int cancompress = 1;
+ int next_tail;
+#endif
+
+/* do I have such a thing as a null event? */
+
+ dev = file->private_data;
+
+ /* verify that we actually have some data to read */
+ if (count == 0)
+ goto exit;
+
+ /* lock this object */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d\n", retval);
+ goto unlock_exit;
+ }
+
+ while (dev->ring_head == dev->ring_tail) {
+
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ // atomic_cmp_exchange(&dev->interrupt_in_done,0,0);
+ dev->interrupt_in_done = 0 ; /* tiny race - FIXME: make atomic? */
+ retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
+ if (retval < 0) {
+ goto unlock_exit;
+ }
+ }
+
+ dbg_info(&dev->intf->dev, "%s: copying to userspace: %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+
+#if BUFFERED_READS
+ c = 0;
+ while((c < count) && (dev->ring_tail != dev->ring_head)) {
+
+/* This started off in the lower level service routine, and I moved it here. Then my brain died. Not done yet. */
+#if COMPRESS_WHEEL_EVENTS
+ next_tail = (dev->ring_tail+1) % ring_buffer_size;
+ if(dev->compress_wheel) cancompress = 1;
+ while(dev->ring_head != next_tail && cancompress == 1 ) {
+ newwheel = (*dev->ring_buffer)[next_tail].cmd[6];
+ oldwheel = (*dev->ring_buffer)[dev->ring_tail].cmd[6];
+ // if both are wheel events, and no buttons have changes (FIXME, do I have to check?),
+ // and we are the same sign, we can compress +- 7F
+ // FIXME: saner check for overflow! - max of +- 7F
+ // FIXME the math is wrong for going in reverse, actually, as the midi spec doesn't allow signed chars
+
+ dbg_info(&dev->intf->dev, "%s: trying to compress: %02x%02x%02x%02x%02x %02x %02x %02x\n",
+ __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+
+
+ if(((*dev->ring_buffer)[dev->ring_tail].cmd[6] != 0 &&
+ (*dev->ring_buffer)[next_tail].cmd[6] != 0 ) &&
+ ((newwheel > 0 && oldwheel > 0) ||
+ (newwheel < 0 && oldwheel < 0)) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[2] == (*dev->ring_buffer)[next_tail].cmd[2]) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[3] == (*dev->ring_buffer)[next_tail].cmd[3]) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[4] == (*dev->ring_buffer)[next_tail].cmd[4]) &&
+ ((*dev->ring_buffer)[dev->ring_tail].cmd[5] == (*dev->ring_buffer)[next_tail].cmd[5]))
+ {
+ dbg_info(&dev->intf->dev, "%s: should compress: %02x%02x%02x%02x%02x%02x%02x%02x\n",
+ __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+
+ newwheel += oldwheel;
+ if(oldwheel > 0 && !(newwheel > 0)) {
+ newwheel = 0x7f;
+ cancompress = 0;
+ }
+ if(oldwheel < 0 && !(newwheel < 0)) {
+ newwheel = 0x80;
+ cancompress = 0;
+ }
+
+ (*dev->ring_buffer)[next_tail].cmd[6] = newwheel;
+ dev->ring_tail = next_tail;
+ next_tail = (dev->ring_tail+1) % ring_buffer_size;
+ } else {
+ cancompress = 0;
+ }
+ }
+#endif /* COMPRESS_WHEEL_EVENTS */
+
+ if (copy_to_user(&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], 8)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
+ c+=8;
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ }
+ retval = c;
+
+#else
+ if (copy_to_user(buffer, &(*dev->ring_buffer)[dev->ring_tail], 8)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+
+ retval = 8;
+#endif /* BUFFERED_READS */
+
+unlock_exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/**
+ * usb_tranzport_write
+ */
+static ssize_t usb_tranzport_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct usb_tranzport *dev;
+ size_t bytes_to_write;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ /* verify that we actually have some data to write */
+ if (count == 0)
+ goto exit;
+
+ /* lock this object */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d\n", retval);
+ goto unlock_exit;
+ }
+
+ /* wait until previous transfer is finished */
+ if (dev->interrupt_out_busy) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy);
+ if (retval < 0) {
+ goto unlock_exit;
+ }
+ }
+
+ /* write the data into interrupt_out_buffer from userspace */
+ bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
+ if (bytes_to_write < count)
+ dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
+
+ dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
+
+ if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ if (dev->interrupt_out_endpoint == NULL) {
+ err("Endpoint should not be be null! \n");
+ goto unlock_exit;
+ }
+
+ /* send off the urb */
+ usb_fill_int_urb(dev->interrupt_out_urb,
+ interface_to_usbdev(dev->intf),
+ usb_sndintpipe(interface_to_usbdev(dev->intf),
+ dev->interrupt_out_endpoint->bEndpointAddress),
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ usb_tranzport_interrupt_out_callback,
+ dev,
+ dev->interrupt_out_interval);
+
+ dev->interrupt_out_busy = 1;
+ wmb();
+
+ retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
+ if (retval) {
+ dev->interrupt_out_busy = 0;
+ err("Couldn't submit interrupt_out_urb %d\n", retval);
+ goto unlock_exit;
+ }
+ retval = bytes_to_write;
+
+unlock_exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/* file operations needed when we register this driver */
+static const struct file_operations usb_tranzport_fops = {
+ .owner = THIS_MODULE,
+ .read = usb_tranzport_read,
+ .write = usb_tranzport_write,
+ .open = usb_tranzport_open,
+ .release = usb_tranzport_release,
+ .poll = usb_tranzport_poll,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with the driver core
+ */
+static struct usb_class_driver usb_tranzport_class = {
+ .name = "tranzport%d",
+ .fops = &usb_tranzport_fops,
+ .minor_base = USB_TRANZPORT_MINOR_BASE,
+};
+
+
+/**
+ * usb_tranzport_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int usb_tranzport_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_tranzport *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int i;
+ int true_size;
+ int retval = -ENOMEM;
+
+ /* allocate memory for our device state and intialize it */
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&intf->dev, "Out of memory\n");
+ goto exit;
+ }
+ init_MUTEX(&dev->sem);
+ dev->intf = intf;
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+
+ iface_desc = intf->cur_altsetting;
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint))
+ dev->interrupt_in_endpoint = endpoint;
+
+ if (usb_endpoint_is_int_out(endpoint))
+ dev->interrupt_out_endpoint = endpoint;
+ }
+ if (dev->interrupt_in_endpoint == NULL) {
+ dev_err(&intf->dev, "Interrupt in endpoint not found\n");
+ goto error;
+ }
+ if (dev->interrupt_out_endpoint == NULL)
+ dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
+
+
+ dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+
+ if (dev->interrupt_in_endpoint_size != 8)
+ dev_warn(&intf->dev, "Interrupt in endpoint size is not 8!\n");
+
+ if(ring_buffer_size == 0) { ring_buffer_size = RING_BUFFER_SIZE; }
+ true_size = min(ring_buffer_size,RING_BUFFER_SIZE);
+ /* FIXME - there are more usb_alloc routines for dma correctness. Needed? */
+
+ dev->ring_buffer = kmalloc((true_size*sizeof(struct tranzport_cmd))+8, GFP_KERNEL);
+
+ if (!dev->ring_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate ring_buffer of size %d\n",true_size);
+ goto error;
+ }
+ dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
+ if (!dev->interrupt_in_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n");
+ goto error;
+ }
+ dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_in_urb) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
+ udev->descriptor.bMaxPacketSize0;
+
+ if (dev->interrupt_out_endpoint_size !=8)
+ dev_warn(&intf->dev, "Interrupt out endpoint size is not 8!)\n");
+
+ dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
+ if (!dev->interrupt_out_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n");
+ goto error;
+ }
+ dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_out_urb) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n");
+ goto error;
+ }
+ dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
+ if (dev->interrupt_out_endpoint)
+ dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(intf, dev);
+
+ retval = usb_register_dev(intf, &usb_tranzport_class);
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&intf->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(intf, NULL);
+ goto error;
+ }
+
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightRecord))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackrec))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackmute))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightTracksolo))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightAnysolo))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightLoop))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_LightPunch))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_wheel))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_event))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_dump_state))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_compress_wheel))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_enable))) goto error;
+ if((retval = device_create_file(&intf->dev, &dev_attr_offline))) goto error;
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&intf->dev, "Tranzport Device #%d now attached to major %d minor %d\n",
+ (intf->minor - USB_TRANZPORT_MINOR_BASE), USB_MAJOR, intf->minor);
+
+exit:
+ return retval;
+
+error:
+ usb_tranzport_delete(dev);
+
+ return retval;
+}
+
+/**
+ * usb_tranzport_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void usb_tranzport_disconnect(struct usb_interface *intf)
+{
+ struct usb_tranzport *dev;
+ int minor;
+
+ /* FIXME: The skel code calls lock_kernel here, doesn't use a mutex, needed? */
+ mutex_lock(&disconnect_mutex);
+
+ dev = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ down(&dev->sem);
+
+ minor = intf->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(intf, &usb_tranzport_class);
+
+ /* if the device is not opened, then we clean up right now */
+ if (!dev->open_count) {
+ up(&dev->sem);
+ usb_tranzport_delete(dev);
+ } else {
+ dev->intf = NULL;
+ up(&dev->sem);
+ }
+
+ mutex_unlock(&disconnect_mutex);
+
+ dev_info(&intf->dev, "Tranzport Surface #%d now disconnected\n",
+ (minor - USB_TRANZPORT_MINOR_BASE));
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver usb_tranzport_driver = {
+ .name = "tranzport",
+ .probe = usb_tranzport_probe,
+ .disconnect = usb_tranzport_disconnect,
+ .id_table = usb_tranzport_table,
+};
+
+/**
+ * usb_tranzport_init
+ */
+static int __init usb_tranzport_init(void)
+{
+ int retval;
+
+ /* register this driver with the USB subsystem */
+ retval = usb_register(&usb_tranzport_driver);
+ if (retval)
+ err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
+
+ return retval;
+}
+
+/**
+ * usb_tranzport_exit
+ */
+static void __exit usb_tranzport_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&usb_tranzport_driver);
+}
+
+module_init(usb_tranzport_init);
+module_exit(usb_tranzport_exit);
+
diff --git a/libs/surfaces/frontier/tests/Makefile b/libs/surfaces/frontier/tests/Makefile
new file mode 100644
index 0000000000..aafb9aaa57
--- /dev/null
+++ b/libs/surfaces/frontier/tests/Makefile
@@ -0,0 +1,17 @@
+# Some basic utilities for testing the tranzport's I/O
+# eventually "tranzport" will become a flexible command
+#
+#
+all: tranzport tranzport_lights
+
+tranzport: tranzport.c
+ gcc -g -Wall -o tranzport tranzport.c
+
+tranzport_lights: tranzport_lights.c
+ gcc -g -Wall -o tranzport_lights tranzport_lights.c
+
+clean::
+ rm -f core .*.cmd *.o *.ko *.mod.c Module.symvers *.bak .\#* *~
+ rm -rf .tmp_versions tranzport tranzport_lights
+
+
diff --git a/libs/surfaces/frontier/tests/README b/libs/surfaces/frontier/tests/README
new file mode 100644
index 0000000000..f9efd18f69
--- /dev/null
+++ b/libs/surfaces/frontier/tests/README
@@ -0,0 +1,104 @@
+tranzport 0.1
+oct 18, 2005
+arthur@artcmusic.com
+---
+
+The Frontier Design Tranzport(tm) (www.frontierdesign.com) is a simple
+wireless USB device. It is not a MIDI device. The document on their web
+site "Tranzport(tm) Native Mode Interface Description" describes the
+Tranzport(tm) as if it were a MIDI device, but this is implemented by their
+Windows and Macintosh software drivers.
+
+This code will allow you to use your Tranzport(tm) at a lower level of
+abstraction. This code relies on libusb, which can be obtained from
+libusb.sourceforge.net.
+
+To compile the program, type "make". You should end up with a executable
+called "tranzport". You'll probably have to run this program as root.
+
+Using the program is straightforward. It will simply tell you which
+buttons are being pressed and what not. If you press one of the buttons
+with a light, the light will turn on. If you hold shift and press one of
+the buttons with a light, the light will turn off. If you take out the
+batteries to the device (or go out of range), it will tell you that the
+device is offline. When you replace the batteries (or come back in
+range), it should tell you it is back online.
+
+Once you understand how everything works, you should be able to
+incorporate it into your own setup however you wish.
+
+This code was developed on a Linux machine, but (theoretically) it
+should work on any system that is supported by libusb, since that is how
+it communicates with the device.
+
+Here are a few more details about the device:
+
+There are two endpoints for communication with the device. All data
+reads and writes are done in 8-byte segments.
+
+One endpoint is for interrupt reads. This is used to read button data
+from the device. It also supplies status information for when the device
+goes out of range and comes back in range, loses power and regains
+power, etc. The format of the data is:
+
+ 00 ss bb bb bb bb dd 00 (hexadecimal)
+
+where:
+
+ ss - status code, 01=online ff=offline
+ bb - button bits
+ dd - data wheel, 01-3f=forward 41-7f=backward
+
+Please refer to the source code for a list of the button bits.
+
+The other endpoint is for interrupt writes. This is used to toggle the
+lights on the device, and to write data to the LCD.
+
+There are 7 lights on the device. To turn a light on, send the following
+sequence of bytes:
+
+ 00 00 nn 01 00 00 00 00 (hexadecimal)
+
+where nn is the light number.
+
+To turn a light off:
+
+ 00 00 nn 00 00 00 00 00 (hexadecimal)
+
+Here is the list of lights:
+
+ 00 Record
+ 01 Track Rec
+ 02 Track Mute
+ 03 Track Solo
+ 04 Any Solo
+ 05 Loop
+ 06 Punch
+
+The size of the LCD is 20x2, and it is split into 10 cells, each cell
+being 4 characters wide. The cells progress across, then down. To write
+to the LCD, send the following sequence of bytes:
+
+ 00 01 cc aa aa aa aa 00 (hexadecimal)
+
+where:
+
+ cc - cell number
+ aa - ASCII code
+
+Here is a list of the cells to clarify:
+
+ 00 row 0, column 0-3
+ 01 row 0, column 4-7
+ 02 row 0, column 8-11
+ 03 row 0, column 12-15
+ 04 row 0, column 16-19
+ 05 row 1, column 0-3
+ 06 row 1, column 4-7
+ 07 row 1, column 8-11
+ 08 row 1, column 12-15
+ 09 row 1, column 16-19
+
+You should refer to the "Tranzport(tm) Native Mode Interface
+Description" document for a listing of the ASCII codes the LCD uses.
+
diff --git a/libs/surfaces/frontier/tests/tranzport.c b/libs/surfaces/frontier/tests/tranzport.c
new file mode 100644
index 0000000000..1eeacd6578
--- /dev/null
+++ b/libs/surfaces/frontier/tests/tranzport.c
@@ -0,0 +1,347 @@
+/*
+ * tranzport 0.1
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+
+struct tranzport_s {
+ struct usb_device *dev;
+ usb_dev_handle *udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core(struct usb_device *dev)
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->dev = dev;
+ z->udev = usb_open(z->dev);
+ if (!z->udev)
+ die("unable to open tranzport");
+
+ val = usb_claim_interface(z->udev, 0);
+ if (val < 0)
+ die("unable to claim tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for(bus=usb_busses; bus; bus=bus->next) {
+ for(dev=bus->devices; dev; dev=dev->next) {
+ if (dev->descriptor.idVendor != VENDORID)
+ continue;
+ if (dev->descriptor.idProduct != PRODUCTID)
+ continue;
+
+ return open_tranzport_core(dev);
+ }
+ }
+
+ die("can't find tranzport");
+ return 0;
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = usb_release_interface(z->udev, 0);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ val = usb_close(z->udev);
+ if (val < 0)
+ log_error("unable to close tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = usb_interrupt_write(z->udev, WRITE_ENDPOINT, cmd, 8, timeout);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0, 8);
+ val = usb_interrupt_read(z->udev, READ_ENDPOINT, buf, 8, timeout);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 1000);
+ } else {
+ tranzport_lighton(z, light, 1000);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons:");
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 1000);
+ tranzport_lcdwrite(z, 1, "DISL", 1000);
+ tranzport_lcdwrite(z, 2, "EXIA", 1000);
+ tranzport_lcdwrite(z, 3, " FOR", 1000);
+ tranzport_lcdwrite(z, 4, " ", 1000);
+
+ tranzport_lcdwrite(z, 5, " ", 1000);
+ tranzport_lcdwrite(z, 6, " CUR", 1000);
+ tranzport_lcdwrite(z, 7, "E FO", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, " ", 1000);
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+ val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline\n");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online\n");
+ do_lcd(z);
+ }
+
+ do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/tests/tranzport_lights.c b/libs/surfaces/frontier/tests/tranzport_lights.c
new file mode 100644
index 0000000000..28a8462d84
--- /dev/null
+++ b/libs/surfaces/frontier/tests/tranzport_lights.c
@@ -0,0 +1,361 @@
+/*
+ * tranzport 0.1
+ * oct 18, 2005
+ * arthur@artcmusic.com
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define VENDORID 0x165b
+#define PRODUCTID 0x8101
+
+#define READ_ENDPOINT 0x81
+#define WRITE_ENDPOINT 0x02
+
+enum {
+ LIGHT_RECORD = 0,
+ LIGHT_TRACKREC,
+ LIGHT_TRACKMUTE,
+ LIGHT_TRACKSOLO,
+ LIGHT_ANYSOLO,
+ LIGHT_LOOP,
+ LIGHT_PUNCH
+};
+
+#define BUTTONMASK_BATTERY 0x00004000
+#define BUTTONMASK_BACKLIGHT 0x00008000
+#define BUTTONMASK_TRACKLEFT 0x04000000
+#define BUTTONMASK_TRACKRIGHT 0x40000000
+#define BUTTONMASK_TRACKREC 0x00040000
+#define BUTTONMASK_TRACKMUTE 0x00400000
+#define BUTTONMASK_TRACKSOLO 0x00000400
+#define BUTTONMASK_UNDO 0x80000000
+#define BUTTONMASK_IN 0x02000000
+#define BUTTONMASK_OUT 0x20000000
+#define BUTTONMASK_PUNCH 0x00800000
+#define BUTTONMASK_LOOP 0x00080000
+#define BUTTONMASK_PREV 0x00020000
+#define BUTTONMASK_ADD 0x00200000
+#define BUTTONMASK_NEXT 0x00000200
+#define BUTTONMASK_REWIND 0x01000000
+#define BUTTONMASK_FASTFORWARD 0x10000000
+#define BUTTONMASK_STOP 0x00010000
+#define BUTTONMASK_PLAY 0x00100000
+#define BUTTONMASK_RECORD 0x00000100
+#define BUTTONMASK_SHIFT 0x08000000
+
+#define STATUS_OFFLINE 0xff
+#define STATUS_ONLINE 0x01
+#define STATUS_OK 0x00
+
+struct tranzport_s {
+ int *dev;
+ int udev;
+};
+
+typedef struct tranzport_s tranzport_t;
+
+void log_entry(FILE *fp, char *format, va_list ap)
+{
+ vfprintf(fp, format, ap);
+ fputc('\n', fp);
+}
+
+void log_error(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ log_entry(stderr, format, ap);
+ va_end(ap);
+}
+
+void vlog_error(char *format, va_list ap)
+{
+ log_entry(stderr, format, ap);
+}
+
+void die(char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_error(format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+tranzport_t *open_tranzport_core()
+{
+ tranzport_t *z;
+ int val;
+
+ z = malloc(sizeof(tranzport_t));
+ if (!z)
+ die("not enough memory");
+ memset(z, 0, sizeof(tranzport_t));
+
+ z->udev = open("/dev/tranzport0",O_RDWR);
+ if (!z->udev)
+ die("unable to open tranzport");
+
+ return z;
+}
+
+tranzport_t *open_tranzport()
+{
+return open_tranzport_core();
+}
+
+void close_tranzport(tranzport_t *z)
+{
+ int val;
+
+ val = close(z->udev);
+ if (val < 0)
+ log_error("unable to release tranzport");
+
+ free(z);
+}
+
+int tranzport_write_core(tranzport_t *z, uint8_t *cmd, int timeout)
+{
+ int val;
+ val = write(z->udev, cmd, 8);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ return 0;
+}
+
+int tranzport_lcdwrite(tranzport_t *z, uint8_t cell, char *text, int timeout)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, cmd, timeout);
+}
+
+int tranzport_lighton(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_lightoff(tranzport_t *z, uint8_t light, int timeout)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return tranzport_write_core(z, &cmd[0], timeout);
+}
+
+int tranzport_read(tranzport_t *z, uint8_t *status, uint32_t *buttons, uint8_t *datawheel, int timeout)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0xff, 8);
+ val = read(z->udev, buf, 8);
+ if (val < 0) {
+ // printf("errno: %d\n",errno);
+ return val;
+ }
+ if (val != 8)
+ return -1;
+
+ /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ *status = buf[1];
+
+ *buttons = 0;
+ *buttons |= buf[2] << 24;
+ *buttons |= buf[3] << 16;
+ *buttons |= buf[4] << 8;
+ *buttons |= buf[5];
+
+ *datawheel = buf[6];
+
+ return 0;
+}
+
+void lights_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, uint8_t light)
+{
+ if (buttons & buttonmask) {
+ if (buttons & BUTTONMASK_SHIFT) {
+ tranzport_lightoff(z, light, 1000);
+ } else {
+ tranzport_lighton(z, light, 1000);
+ }
+ }
+}
+
+void do_lights(tranzport_t *z, uint32_t buttons)
+{
+ lights_core(z, buttons, BUTTONMASK_RECORD, LIGHT_RECORD);
+ lights_core(z, buttons, BUTTONMASK_TRACKREC, LIGHT_TRACKREC);
+ lights_core(z, buttons, BUTTONMASK_TRACKMUTE, LIGHT_TRACKMUTE);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_TRACKSOLO);
+ lights_core(z, buttons, BUTTONMASK_TRACKSOLO, LIGHT_ANYSOLO);
+ lights_core(z, buttons, BUTTONMASK_PUNCH, LIGHT_PUNCH);
+ lights_core(z, buttons, BUTTONMASK_LOOP, LIGHT_LOOP);
+}
+
+void buttons_core(tranzport_t *z, uint32_t buttons, uint32_t buttonmask, char *str)
+{
+ if (buttons & buttonmask)
+ printf(" %s", str);
+}
+
+void do_buttons(tranzport_t *z, uint32_t buttons, uint8_t datawheel)
+{
+ printf("buttons: %x ", buttons);
+ buttons_core(z, buttons, BUTTONMASK_BATTERY, "battery");
+ buttons_core(z, buttons, BUTTONMASK_BACKLIGHT, "backlight");
+ buttons_core(z, buttons, BUTTONMASK_TRACKLEFT, "trackleft");
+ buttons_core(z, buttons, BUTTONMASK_TRACKRIGHT, "trackright");
+ buttons_core(z, buttons, BUTTONMASK_TRACKREC, "trackrec");
+ buttons_core(z, buttons, BUTTONMASK_TRACKMUTE, "trackmute");
+ buttons_core(z, buttons, BUTTONMASK_TRACKSOLO, "tracksolo");
+ buttons_core(z, buttons, BUTTONMASK_UNDO, "undo");
+ buttons_core(z, buttons, BUTTONMASK_IN, "in");
+ buttons_core(z, buttons, BUTTONMASK_OUT, "out");
+ buttons_core(z, buttons, BUTTONMASK_PUNCH, "punch");
+ buttons_core(z, buttons, BUTTONMASK_LOOP, "loop");
+ buttons_core(z, buttons, BUTTONMASK_PREV, "prev");
+ buttons_core(z, buttons, BUTTONMASK_ADD, "add");
+ buttons_core(z, buttons, BUTTONMASK_NEXT, "next");
+ buttons_core(z, buttons, BUTTONMASK_REWIND, "rewind");
+ buttons_core(z, buttons, BUTTONMASK_FASTFORWARD, "fastforward");
+ buttons_core(z, buttons, BUTTONMASK_STOP, "stop");
+ buttons_core(z, buttons, BUTTONMASK_PLAY, "play");
+ buttons_core(z, buttons, BUTTONMASK_RECORD, "record");
+ buttons_core(z, buttons, BUTTONMASK_SHIFT, "shift");
+ if (datawheel)
+ printf(" datawheel=%02x", datawheel);
+ printf("\n");
+}
+
+void do_lcd(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, " ", 1000);
+ tranzport_lcdwrite(z, 1, "DISL", 1000);
+ tranzport_lcdwrite(z, 2, "EXIA", 1000);
+ tranzport_lcdwrite(z, 3, " FOR", 1000);
+ tranzport_lcdwrite(z, 4, " ", 1000);
+
+ tranzport_lcdwrite(z, 5, " ", 1000);
+ tranzport_lcdwrite(z, 6, " CUR", 1000);
+ tranzport_lcdwrite(z, 7, "E FO", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, " ", 1000);
+}
+
+void do_lcd2(tranzport_t *z)
+{
+ tranzport_lcdwrite(z, 0, "THE ", 1000);
+ tranzport_lcdwrite(z, 1, "TRAN", 1000);
+ tranzport_lcdwrite(z, 2, "ZPOR", 1000);
+ tranzport_lcdwrite(z, 3, "T RO", 1000);
+ tranzport_lcdwrite(z, 4, " KS", 1000);
+
+ tranzport_lcdwrite(z, 5, "AWES", 1000);
+ tranzport_lcdwrite(z, 6, "OMEE", 1000);
+ tranzport_lcdwrite(z, 7, "LEEE", 1000);
+ tranzport_lcdwrite(z, 8, "UND ", 1000);
+ tranzport_lcdwrite(z, 9, "GROK", 1000);
+}
+
+lights_off(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lightoff(z, i, 1000);
+ }
+}
+
+lights_on(tranzport_t *z) {
+int i;
+ for(i=0;i<7;i++) {
+ tranzport_lighton(z, i, 1000);
+ }
+}
+
+int main()
+{
+ tranzport_t *z;
+ uint8_t status;
+ uint32_t buttons;
+ uint8_t datawheel;
+ int val;
+
+ z = open_tranzport();
+
+ do_lcd(z);
+
+ for(;;) {
+
+ do_lcd(z);
+ lights_on(z);
+ do_lcd2(z);
+ lights_off(z);
+
+// val = tranzport_read(z, &status, &buttons, &datawheel, 60000);
+ val = -1;
+ if (val < 0)
+ continue;
+
+ if (status == STATUS_OFFLINE) {
+ printf("offline: ");
+ continue;
+ }
+
+ if (status == STATUS_ONLINE) {
+ printf("online: ");
+ do_lcd(z);
+ }
+
+ do_lights(z, buttons);
+ do_buttons(z, buttons, datawheel);
+ }
+
+ close_tranzport(z);
+
+ return 0;
+}
+
diff --git a/libs/surfaces/frontier/tranzport/SConscript b/libs/surfaces/frontier/tranzport/SConscript
new file mode 100644
index 0000000000..5d390f3e2f
--- /dev/null
+++ b/libs/surfaces/frontier/tranzport/SConscript
@@ -0,0 +1,56 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+tranzport = env.Copy()
+
+#
+# this defines the version number of libardour_tranzport
+#
+
+domain = 'ardour_tranzport'
+
+tranzport.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+tranzport.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+tranzport.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+tranzport.Append(PACKAGE = domain)
+tranzport.Append(POTFILE = domain + '.pot')
+
+tranzport_files=Split("""
+interface.cc
+tranzport_control_protocol.cc
+""")
+
+tranzport.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+tranzport.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+tranzport.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+tranzport.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+tranzport.Merge ([
+ libraries['ardour'],
+ libraries['ardour_cp'],
+ libraries['sigc2'],
+ libraries['pbd'],
+ libraries['midi++2'],
+ libraries['xml'],
+ libraries['usb'],
+ libraries['glib2'],
+ libraries['glibmm2']
+ ])
+
+libardour_tranzport = tranzport.SharedLibrary('ardour_tranzport', tranzport_files)
+
+if tranzport['TRANZPORT']:
+ Default(libardour_tranzport)
+ if env['NLS']:
+ i18n (tranzport, tranzport_files, env)
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_tranzport))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript' ] +
+ tranzport_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/frontier/tranzport/interface.cc b/libs/surfaces/frontier/tranzport/interface.cc
new file mode 100644
index 0000000000..f6d0dc8206
--- /dev/null
+++ b/libs/surfaces/frontier/tranzport/interface.cc
@@ -0,0 +1,51 @@
+#include
+#include "tranzport_control_protocol.h"
+
+using namespace ARDOUR;
+
+ControlProtocol*
+new_tranzport_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ TranzportControlProtocol* tcp = new TranzportControlProtocol (*s);
+
+ if (tcp->set_active (true)) {
+ delete tcp;
+ return 0;
+ }
+
+ return tcp;
+
+}
+
+void
+delete_tranzport_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+bool
+probe_tranzport_protocol (ControlProtocolDescriptor* descriptor)
+{
+ return TranzportControlProtocol::probe();
+}
+
+static ControlProtocolDescriptor tranzport_descriptor = {
+ name : "Tranzport",
+ id : "uri://ardour.org/surfaces/tranzport:0",
+ ptr : 0,
+ module : 0,
+ mandatory : 0,
+ supports_feedback : false,
+ probe : probe_tranzport_protocol,
+ initialize : new_tranzport_protocol,
+ destroy : delete_tranzport_protocol
+};
+
+
+extern "C" {
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &tranzport_descriptor;
+}
+}
+
diff --git a/libs/surfaces/tranzport/tranzport_control_protocol.cc b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
similarity index 99%
rename from libs/surfaces/tranzport/tranzport_control_protocol.cc
rename to libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
index bbb78d31d1..b0c03fb71e 100644
--- a/libs/surfaces/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
@@ -15,7 +15,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
+ $Id: tranzport_control_protocol.cc 1252 2006-12-29 19:13:18Z sampo $
*/
/* Design notes: The tranzport is a unique device, basically a
@@ -1562,7 +1562,7 @@ TranzportControlProtocol::button_event_record_release (bool shifted)
void button_event_mute (bool pressed, bool shifted)
{
- //static int was_pressed = 0;
+ static int was_pressed = 0;
// if(pressed) { }
}
diff --git a/libs/surfaces/frontier/tranzport/tranzport_control_protocol.h b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.h
new file mode 100644
index 0000000000..f13e4a3a44
--- /dev/null
+++ b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.h
@@ -0,0 +1,320 @@
+
+#ifndef ardour_tranzport_control_protocol_h
+#define ardour_tranzport_control_protocol_h
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+
+class TranzportControlProtocol : public ARDOUR::ControlProtocol
+{
+ public:
+ TranzportControlProtocol (ARDOUR::Session&);
+ virtual ~TranzportControlProtocol();
+
+ int set_active (bool yn);
+
+ static bool probe ();
+
+ XMLNode& get_state ();
+ int set_state (const XMLNode&);
+
+ private:
+ static const int VENDORID = 0x165b;
+ static const int PRODUCTID = 0x8101;
+ static const int READ_ENDPOINT = 0x81;
+ static const int WRITE_ENDPOINT = 0x02;
+ const static int STATUS_OFFLINE = 0xff;
+ const static int STATUS_ONLINE = 0x01;
+ const static uint8_t WheelDirectionThreshold = 0x3f;
+
+ enum LightID {
+ LightRecord = 0,
+ LightTrackrec,
+ LightTrackmute,
+ LightTracksolo,
+ LightAnysolo,
+ LightLoop,
+ LightPunch
+ };
+
+ enum ButtonID {
+ ButtonBattery = 0x00004000,
+ ButtonBacklight = 0x00008000,
+ ButtonTrackLeft = 0x04000000,
+ ButtonTrackRight = 0x40000000,
+ ButtonTrackRec = 0x00040000,
+ ButtonTrackMute = 0x00400000,
+ ButtonTrackSolo = 0x00000400,
+ ButtonUndo = 0x80000000,
+ ButtonIn = 0x02000000,
+ ButtonOut = 0x20000000,
+ ButtonPunch = 0x00800000,
+ ButtonLoop = 0x00080000,
+ ButtonPrev = 0x00020000,
+ ButtonAdd = 0x00200000,
+ ButtonNext = 0x00000200,
+ ButtonRewind = 0x01000000,
+ ButtonFastForward = 0x10000000,
+ ButtonStop = 0x00010000,
+ ButtonPlay = 0x00100000,
+ ButtonRecord = 0x00000100,
+ ButtonShift = 0x08000000
+ };
+
+ enum WheelShiftMode {
+ WheelShiftGain,
+ WheelShiftPan,
+ WheelShiftMaster,
+ WheelShiftMarker
+ };
+
+ enum WheelMode {
+ WheelTimeline,
+ WheelScrub,
+ WheelShuttle
+ };
+
+ // FIXME - look at gtk2_ardour for snap settings
+
+ enum WheelIncrement {
+ WheelIncrSlave,
+ WheelIncrScreen,
+ WheelIncrSample,
+ WheelIncrBeat,
+ WheelIncrBar,
+ WheelIncrSecond,
+ WheelIncrMinute
+ };
+
+ enum DisplayMode {
+ DisplayNormal,
+ DisplayRecording,
+ DisplayRecordingMeter,
+ DisplayBigMeter,
+ DisplayConfig,
+ DisplayBling,
+ DisplayBlingMeter
+ };
+
+ enum BlingMode {
+ BlingOff,
+ BlingKit,
+ BlingRotating,
+ BlingPairs,
+ BlingRows,
+ BlingFlashAll
+ };
+
+ pthread_t thread;
+ uint32_t buttonmask;
+ uint32_t timeout;
+ uint32_t inflight;
+ uint8_t _datawheel;
+ uint8_t _device_status;
+ uint32_t current_track_id;
+ WheelMode wheel_mode;
+ WheelShiftMode wheel_shift_mode;
+ DisplayMode display_mode;
+ BlingMode bling_mode;
+ WheelIncrement wheel_increment;
+ usb_dev_handle* udev;
+
+ ARDOUR::gain_t gain_fraction;
+
+ Glib::Mutex update_lock;
+
+ bool screen_invalid[2][20];
+ char screen_current[2][20];
+ char screen_pending[2][20];
+ char screen_flash[2][20];
+
+ bool lights_invalid[7];
+ bool lights_current[7];
+ bool lights_pending[7];
+ bool lights_flash[7];
+
+ uint32_t last_bars;
+ uint32_t last_beats;
+ uint32_t last_ticks;
+
+ bool last_negative;
+ uint32_t last_hrs;
+ uint32_t last_mins;
+ uint32_t last_secs;
+ uint32_t last_frames;
+ nframes_t last_where;
+ ARDOUR::gain_t last_track_gain;
+ uint32_t last_meter_fill;
+ struct timeval last_wheel_motion;
+ int last_wheel_dir;
+
+ Glib::Mutex io_lock;
+
+ int open ();
+ int read (uint8_t *buf,uint32_t timeout_override = 0);
+ int write (uint8_t* cmd, uint32_t timeout_override = 0);
+ int write_noretry (uint8_t* cmd, uint32_t timeout_override = 0);
+ int close ();
+ int save(char *name = "default");
+ int load(char *name = "default");
+ void print (int row, int col, const char* text);
+ void print_noretry (int row, int col, const char* text);
+
+ int rtpriority_set(int priority = 52);
+ int rtpriority_unset(int priority = 0);
+
+ int open_core (struct usb_device*);
+
+ static void* _monitor_work (void* arg);
+ void* monitor_work ();
+
+ int process (uint8_t *);
+ int update_state();
+ void invalidate();
+ int flush();
+ // bool isuptodate(); // think on this. It seems futile to update more than 30/sec
+
+ // A screen is a cache of what should be on the lcd
+
+ void screen_init();
+ void screen_validate();
+ void screen_invalidate();
+ int screen_flush();
+ void screen_clear();
+ // bool screen_isuptodate(); // think on this -
+
+ // Commands to write to the lcd
+
+ int lcd_init();
+ bool lcd_damage();
+ bool lcd_isdamaged();
+
+ bool lcd_damage(int row, int col = 0, int length = 20);
+ bool lcd_isdamaged(int row, int col = 0, int length = 20);
+
+ int lcd_flush();
+ int lcd_write(uint8_t* cmd, uint32_t timeout_override = 0); // pedantic alias for write
+ void lcd_fill (uint8_t fill_char);
+ void lcd_clear ();
+ void lcd_print (int row, int col, const char* text);
+ void lcd_print_noretry (int row, int col, const char* text);
+
+ // Commands to write to the lights
+ // FIXME - on some devices lights can have intensity and colors
+
+ void lights_init();
+ void lights_validate();
+ void lights_invalidate();
+ void light_validate(LightID light);
+ void light_invalidate(LightID light);
+ int lights_flush();
+ int lights_write(uint8_t* cmd,uint32_t timeout_override = 0); // pedantic alias to write
+
+ // a cache of what should be lit
+
+ void lights_off ();
+ void lights_on ();
+ int light_set(LightID, bool offon = true);
+ int light_on (LightID);
+ int light_off (LightID);
+
+ // some modes for the lights, should probably be renamed
+
+ int lights_show_normal();
+ int lights_show_recording();
+ int lights_show_tempo();
+ int lights_show_bling();
+
+ void enter_big_meter_mode ();
+ void enter_normal_display_mode ();
+ void enter_config_mode();
+ void enter_recording_mode();
+ void enter_bling_mode();
+
+ void next_display_mode ();
+ void normal_update ();
+
+ void show_current_track ();
+ void show_track_gain ();
+ void show_transport_time ();
+ void show_bbt (nframes_t where);
+ void show_smpte (nframes_t where);
+ void show_wheel_mode ();
+ void show_gain ();
+ void show_pan ();
+ void show_meter ();
+
+ void datawheel ();
+ void scrub ();
+ void scroll ();
+ void shuttle ();
+ void config ();
+
+ void next_wheel_mode ();
+ void next_wheel_shift_mode ();
+
+ void set_current_track (ARDOUR::Route*);
+ void next_track ();
+ void prev_track ();
+ void step_gain_up ();
+ void step_gain_down ();
+ void step_pan_right ();
+ void step_pan_left ();
+
+
+ void button_event_battery_press (bool shifted);
+ void button_event_battery_release (bool shifted);
+ void button_event_backlight_press (bool shifted);
+ void button_event_backlight_release (bool shifted);
+ void button_event_trackleft_press (bool shifted);
+ void button_event_trackleft_release (bool shifted);
+ void button_event_trackright_press (bool shifted);
+ void button_event_trackright_release (bool shifted);
+ void button_event_trackrec_press (bool shifted);
+ void button_event_trackrec_release (bool shifted);
+ void button_event_trackmute_press (bool shifted);
+ void button_event_trackmute_release (bool shifted);
+ void button_event_tracksolo_press (bool shifted);
+ void button_event_tracksolo_release (bool shifted);
+ void button_event_undo_press (bool shifted);
+ void button_event_undo_release (bool shifted);
+ void button_event_in_press (bool shifted);
+ void button_event_in_release (bool shifted);
+ void button_event_out_press (bool shifted);
+ void button_event_out_release (bool shifted);
+ void button_event_punch_press (bool shifted);
+ void button_event_punch_release (bool shifted);
+ void button_event_loop_press (bool shifted);
+ void button_event_loop_release (bool shifted);
+ void button_event_prev_press (bool shifted);
+ void button_event_prev_release (bool shifted);
+ void button_event_add_press (bool shifted);
+ void button_event_add_release (bool shifted);
+ void button_event_next_press (bool shifted);
+ void button_event_next_release (bool shifted);
+ void button_event_rewind_press (bool shifted);
+ void button_event_rewind_release (bool shifted);
+ void button_event_fastforward_press (bool shifted);
+ void button_event_fastforward_release (bool shifted);
+ void button_event_stop_press (bool shifted);
+ void button_event_stop_release (bool shifted);
+ void button_event_play_press (bool shifted);
+ void button_event_play_release (bool shifted);
+ void button_event_record_press (bool shifted);
+ void button_event_record_release (bool shifted);
+
+ // new api
+ void button_event_mute (bool pressed, bool shifted);
+};
+
+
+#endif // ardour_tranzport_control_protocol_h
diff --git a/libs/surfaces/generic_midi/SConscript b/libs/surfaces/generic_midi/SConscript
index 6c76e05464..b092188852 100644
--- a/libs/surfaces/generic_midi/SConscript
+++ b/libs/surfaces/generic_midi/SConscript
@@ -40,8 +40,8 @@ genericmidi.Merge ([
libraries['sigc2'],
libraries['usb'],
libraries['xml'],
- libraries['glib2'],
- libraries['glibmm2']
+ libraries['glib2'],
+ libraries['glibmm2']
])
libardour_genericmidi = genericmidi.SharedLibrary('ardour_genericmidi', genericmidi_files)
diff --git a/libs/surfaces/mackie/SConscript b/libs/surfaces/mackie/SConscript
new file mode 100644
index 0000000000..bdebf2a54d
--- /dev/null
+++ b/libs/surfaces/mackie/SConscript
@@ -0,0 +1,73 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+mackie = env.Copy()
+
+#
+# this defines the version number of libardour_mackie
+#
+
+domain = 'ardour_mackie'
+
+mackie.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+mackie.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+mackie.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+mackie.Append(PACKAGE = domain)
+mackie.Append(POTFILE = domain + '.pot')
+
+mackie_files=Split("""
+interface.cc
+midi_byte_array.cc
+controls.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
+mackie_surface.cc
+""")
+
+mackie.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+mackie.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+mackie.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+mackie.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+mackie.Merge ([
+ libraries['ardour'],
+ libraries['ardour_cp'],
+ libraries['sigc2'],
+ libraries['pbd'],
+ libraries['midi++2'],
+ libraries['xml'],
+ libraries['glib2'],
+ libraries['glibmm2']
+ ])
+
+libardour_mackie = mackie.SharedLibrary('ardour_mackie', mackie_files)
+
+test_files = Split("""
+midi_byte_array.cc
+test.cc
+""")
+mackie_test = Program('mackie_test', test_files )
+
+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'], 'ardour2','surfaces'), libardour_mackie))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript' ] +
+ mackie_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/mackie/TODO b/libs/surfaces/mackie/TODO
new file mode 100644
index 0000000000..5164c9acda
--- /dev/null
+++ b/libs/surfaces/mackie/TODO
@@ -0,0 +1,44 @@
+* 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.
+
+* occasional hang on startup. deadlock?
+* finish button mapping
+* discuss button mapping for Ardour
+* concurrency for bank switching? And make sure "old" events aren't sent to "new" faders
+* concurrency in write( bytes ). Queueing?
+* Are remote_ids supposed to be 1-based or 0-based?
+* TODOs in code
+* handle remote_control_id changed signal from Route.
+* handle removal of route. Need another session signal?
+* Some indication on the UI of remote_ids?
+ Useful for surfaces that don't have a scribble strip.
+* use i18n. see string_compose
+* MackieControlProtocol in namespace Mackie?
+* Generic surface code to common location
+* power-cycling of surface. fd_midiport doesn't close.
+* remove couts
+* jog with transport rolling doesn't work properly
+
+Later
+-----
+* which bank switching - overlap or dead faders? Option?
+* signals for buttons?
+
+Actual Mackie
+-------------
+* docs claim that unit will send a host query on init.
+* test Mackie surface object. Apparently led rings don't work
+* timecode & 55 char displays
+* midi bandwidth
+
+Bugs
+----
+
+* get_state isn't called on deactivate
+* close existing and load other session doesn't start control surface
+* set_state is called twice from the control_manager
+* routes "forget" their remote_id between session save and the next session load
+* definitely something wrong with remote_id assignment on session create
+ (master strip assigned 0).
+* gui enables record for tracks with no inputs
diff --git a/libs/surfaces/mackie/bcf_surface.cc b/libs/surfaces/mackie/bcf_surface.cc
new file mode 100644
index 0000000000..6390582bd7
--- /dev/null
+++ b/libs/surfaces/mackie/bcf_surface.cc
@@ -0,0 +1,1458 @@
+/*
+ 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( group );
+
+ group = new Strip ( "strip_1", 0 );
+ groups["strip_1"] = group;
+ strips[0] = dynamic_cast( group );
+
+ group = new Group ( "cursor" );
+ groups["cursor"] = group;
+
+ group = new Strip ( "strip_2", 1 );
+ groups["strip_2"] = group;
+ strips[1] = dynamic_cast( 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( group );
+
+ group = new Group ( "display" );
+ groups["display"] = group;
+
+ group = new Strip ( "strip_4", 3 );
+ groups["strip_4"] = group;
+ strips[3] = dynamic_cast( group );
+
+ group = new Strip ( "strip_5", 4 );
+ groups["strip_5"] = group;
+ strips[4] = dynamic_cast( group );
+
+ group = new Strip ( "strip_6", 5 );
+ groups["strip_6"] = group;
+ strips[5] = dynamic_cast( group );
+
+ group = new Group ( "transport" );
+ groups["transport"] = group;
+
+ group = new Strip ( "strip_7", 6 );
+ groups["strip_7"] = group;
+ strips[6] = dynamic_cast( 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 ( 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 ( 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 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 )
+ {
+ 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 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;
+
+ 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 );
+}
diff --git a/libs/surfaces/mackie/bcf_surface.h b/libs/surfaces/mackie/bcf_surface.h
new file mode 100644
index 0000000000..a5fd3bf5a3
--- /dev/null
+++ b/libs/surfaces/mackie/bcf_surface.h
@@ -0,0 +1,27 @@
+#ifndef mackie_surface_bcf_h
+#define mackie_surface_bcf_h
+/*
+ Generated by scripts/generate-surface.rb
+*/
+
+#include "surface.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler;
+
+class BcfSurface : public Surface
+{
+public:
+ BcfSurface( uint32_t max_strips ) : Surface( max_strips )
+ {
+ }
+
+ virtual void handle_button( MackieButtonHandler & mbh, ButtonState bs, Button & button );
+ virtual void init_controls();
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/controls.cc b/libs/surfaces/mackie/controls.cc
new file mode 100644
index 0000000000..e9808119b2
--- /dev/null
+++ b/libs/surfaces/mackie/controls.cc
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "controls.h"
+#include "types.h"
+#include "mackie_midi_builder.h"
+
+#include
+#include
+#include
+
+using namespace Mackie;
+using namespace std;
+
+void Group::add( Control & control )
+{
+ _controls.push_back( &control );
+}
+
+Strip::Strip( const std::string & name, int index )
+ : Group( name )
+ , _solo( 0 )
+ , _recenable( 0 )
+ , _mute( 0 )
+ , _select( 0 )
+ , _vselect( 0 )
+ , _fader_touch( 0 )
+ , _vpot( 0 )
+ , _gain( 0 )
+ , _index( index )
+{
+}
+
+/**
+ generated with
+
+controls[1].each do |x|
+ puts <
+#include
+#include
+
+#include "mackie_control_exception.h"
+
+namespace Mackie
+{
+
+class Control;
+
+/**
+ This is a loose group of controls, eg cursor buttons,
+ transport buttons, functions buttons etc.
+*/
+class Group
+{
+public:
+ Group( const std::string & name )
+ : _name( name )
+ {
+ }
+
+ virtual ~Group() {}
+
+ virtual bool is_strip() const
+ {
+ return false;
+ }
+
+ virtual bool is_master() const
+ {
+ return false;
+ }
+
+ virtual void add( Control & control );
+
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ // This is for Surface only
+ void name( const std::string & rhs ) { _name = rhs; }
+
+ typedef std::vector Controls;
+ const Controls & controls() const { return _controls; }
+
+protected:
+ Controls _controls;
+
+private:
+ std::string _name;
+};
+
+class Button;
+class Pot;
+class Fader;
+
+/**
+ This is the set of controls that make up a strip.
+*/
+class Strip : public Group
+{
+public:
+ Strip( const std::string & name, int index );
+
+ virtual bool is_strip() const
+ {
+ return true;
+ }
+
+ virtual void add( Control & control );
+
+ /// This is the index of the strip
+ int index() const { return _index; }
+
+ /// This is for Surface only
+ void index( int rhs ) { _index = rhs; }
+
+ Button & solo();
+ Button & recenable();
+ Button & mute();
+ Button & select();
+ Button & vselect();
+ Button & fader_touch();
+ 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; }
+
+private:
+ Button * _solo;
+ Button * _recenable;
+ Button * _mute;
+ Button * _select;
+ Button * _vselect;
+ Button * _fader_touch;
+ Pot * _vpot;
+ Fader * _gain;
+ int _index;
+};
+
+class MasterStrip : public Strip
+{
+public:
+ MasterStrip( const std::string & name, int index )
+ : Strip( name, index )
+ {
+ }
+
+ virtual bool is_master() const
+ {
+ return true;
+ }
+};
+
+class Led;
+
+/**
+ The base class for controls on the surface. They deliberately
+ don't know the midi protocol for updating them.
+*/
+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 )
+ {
+ }
+
+ virtual ~Control() {}
+
+ virtual const Led & led() const
+ {
+ throw MackieControlException( "no led available" );
+ }
+
+ /// The midi id of the control
+ int id() const
+ {
+ return _id;
+ }
+
+ /// The 1-based number of the control
+ int ordinal() const
+ {
+ return _ordinal;
+ }
+
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ const Group & group() const
+ {
+ return _group;
+ }
+
+ const Strip & strip() const
+ {
+ return dynamic_cast( _group );
+ }
+
+ Strip & strip()
+ {
+ return dynamic_cast( _group );
+ }
+
+ virtual bool accepts_feedback() const
+ {
+ return true;
+ }
+
+ virtual type_t type() const = 0;
+
+private:
+ int _id;
+ int _ordinal;
+ std::string _name;
+ Group & _group;
+};
+
+std::ostream & operator << ( std::ostream & os, const Control & control );
+
+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
+{
+public:
+ Led( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ {
+ }
+
+ virtual const Led & led() const { return *this; }
+
+ virtual type_t type() const { return type_led; }
+};
+
+class Button : public Control
+{
+public:
+ Button( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ , _led( id, ordinal, name + "_led", group )
+ {
+ }
+
+ virtual const Led & led() const
+ {
+ return _led;
+ }
+
+ virtual type_t type() const { return type_button; };
+
+private:
+ Led _led;
+};
+
+class LedRing : public Led
+{
+public:
+ LedRing( int id, int ordinal, std::string name, Group & group )
+ : Led( id, ordinal, name, group )
+ {
+ }
+
+ virtual type_t type() const { return type_led_ring; }
+};
+
+class Pot : public Control
+{
+public:
+ Pot( int id, int ordinal, std::string name, Group & group )
+ : Control( id, ordinal, name, group )
+ , _led_ring( id, ordinal, name + "_ring", group )
+ {
+ }
+
+ virtual type_t type() const { return type_pot; }
+
+ virtual const LedRing & led_ring() const
+ {
+ return _led_ring;
+ }
+
+private:
+ LedRing _led_ring;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/interface.cc b/libs/surfaces/mackie/interface.cc
new file mode 100644
index 0000000000..500854fe71
--- /dev/null
+++ b/libs/surfaces/mackie/interface.cc
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2006,2007 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include
+#include "mackie_control_protocol.h"
+
+#include
+
+using namespace ARDOUR;
+using namespace std;
+
+ControlProtocol*
+new_mackie_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ MackieControlProtocol * mcp = 0;
+ try
+ {
+ mcp = new MackieControlProtocol (*s);
+ mcp->set_active( true );
+ }
+ catch( exception & e )
+ {
+ cout << "Error instantiating MackieControlProtocol: " << e.what() << endl;
+ delete mcp;
+ mcp = 0;
+ }
+ return mcp;
+}
+
+void
+delete_mackie_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+bool
+probe_mackie_protocol (ControlProtocolDescriptor* descriptor)
+{
+ return MackieControlProtocol::probe();
+}
+
+static ControlProtocolDescriptor mackie_descriptor = {
+ name : "Mackie",
+ id : "uri://ardour.org/surfaces/mackie:0",
+ ptr : 0,
+ module : 0,
+ mandatory : 0,
+ supports_feedback : true,
+ probe : probe_mackie_protocol,
+ initialize : new_mackie_protocol,
+ destroy : delete_mackie_protocol
+};
+
+
+extern "C" {
+
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &mackie_descriptor;
+}
+
+}
diff --git a/libs/surfaces/mackie/mackie_button_handler.cc b/libs/surfaces/mackie/mackie_button_handler.cc
new file mode 100644
index 0000000000..e1cd9f9153
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_button_handler.cc
@@ -0,0 +1,673 @@
+/*
+ Generated by scripts/generate-button-handlers.erb
+*/
+#include "mackie_button_handler.h"
+#include "controls.h"
+
+#include
+
+using namespace std;
+using namespace Mackie;
+
+LedState MackieButtonHandler::default_button_press( Button & button )
+{
+ cout << "press: " << button << endl;
+ return on;
+}
+LedState MackieButtonHandler::default_button_release( Button & button )
+{
+ cout << "release: " << button << endl;
+ return off;
+}
+
+
+LedState MackieButtonHandler::io_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::io_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::sends_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::sends_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::pan_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::pan_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::plugin_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::plugin_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::eq_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::eq_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::dyn_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::dyn_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::channel_left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::channel_left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::channel_right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::channel_right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::flip_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::flip_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::edit_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::edit_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::name_value_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::name_value_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::smpte_beats_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::smpte_beats_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F1_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F1_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F2_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F2_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F3_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F3_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F4_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F4_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F5_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F5_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F6_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F6_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F7_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F7_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F8_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F8_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F9_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F9_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F10_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F10_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F11_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F11_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F12_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F12_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F13_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F13_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F14_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F14_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F15_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F15_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::F16_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::F16_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::shift_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::shift_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::option_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::option_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::control_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::control_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cmd_alt_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cmd_alt_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::on_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::on_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::rec_ready_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::rec_ready_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::undo_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::undo_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::snapshot_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::snapshot_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::touch_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::touch_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::redo_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::redo_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::marker_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::marker_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::enter_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::enter_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cancel_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cancel_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::mixer_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::mixer_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::frm_left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::frm_left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::frm_right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::frm_right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::loop_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::loop_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::punch_in_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::punch_in_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::punch_out_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::punch_out_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::home_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::home_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::end_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::end_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::rewind_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::rewind_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::ffwd_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::ffwd_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::stop_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::stop_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::play_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::play_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::record_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::record_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_up_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_up_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_down_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_down_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_left_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_left_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::cursor_right_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::cursor_right_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::zoom_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::zoom_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::scrub_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::scrub_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::user_a_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::user_a_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::user_b_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::user_b_release( Button & button )
+{
+ return default_button_release( button );
+}
+
+LedState MackieButtonHandler::fader_touch_press( Button & button )
+{
+ return default_button_press( button );
+}
+
+LedState MackieButtonHandler::fader_touch_release( Button & button )
+{
+ return default_button_release( button );
+}
+
diff --git a/libs/surfaces/mackie/mackie_button_handler.h b/libs/surfaces/mackie/mackie_button_handler.h
new file mode 100644
index 0000000000..a07e98b2fd
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_button_handler.h
@@ -0,0 +1,222 @@
+#ifndef mackie_button_handler_h
+#define mackie_button_handler_h
+/*
+ Generated by scripts/generate-button-handlers.erb
+*/
+
+#include "types.h"
+
+namespace Mackie
+{
+
+class MackieButtonHandler
+{
+public:
+ virtual ~MackieButtonHandler() {}
+
+ virtual LedState default_button_press( Button & button );
+ virtual LedState default_button_release( Button & button );
+
+ virtual void update_led( Button & button, LedState ls ) = 0;
+
+
+ virtual LedState io_press( Button & );
+ virtual LedState io_release( Button & );
+
+ virtual LedState sends_press( Button & );
+ virtual LedState sends_release( Button & );
+
+ virtual LedState pan_press( Button & );
+ virtual LedState pan_release( Button & );
+
+ virtual LedState plugin_press( Button & );
+ virtual LedState plugin_release( Button & );
+
+ virtual LedState eq_press( Button & );
+ virtual LedState eq_release( Button & );
+
+ virtual LedState dyn_press( Button & );
+ virtual LedState dyn_release( Button & );
+
+ virtual LedState left_press( Button & );
+ virtual LedState left_release( Button & );
+
+ virtual LedState right_press( Button & );
+ virtual LedState right_release( Button & );
+
+ virtual LedState channel_left_press( Button & );
+ virtual LedState channel_left_release( Button & );
+
+ virtual LedState channel_right_press( Button & );
+ virtual LedState channel_right_release( Button & );
+
+ virtual LedState flip_press( Button & );
+ virtual LedState flip_release( Button & );
+
+ virtual LedState edit_press( Button & );
+ virtual LedState edit_release( Button & );
+
+ virtual LedState name_value_press( Button & );
+ virtual LedState name_value_release( Button & );
+
+ virtual LedState smpte_beats_press( Button & );
+ virtual LedState smpte_beats_release( Button & );
+
+ virtual LedState F1_press( Button & );
+ virtual LedState F1_release( Button & );
+
+ virtual LedState F2_press( Button & );
+ virtual LedState F2_release( Button & );
+
+ virtual LedState F3_press( Button & );
+ virtual LedState F3_release( Button & );
+
+ virtual LedState F4_press( Button & );
+ virtual LedState F4_release( Button & );
+
+ virtual LedState F5_press( Button & );
+ virtual LedState F5_release( Button & );
+
+ virtual LedState F6_press( Button & );
+ virtual LedState F6_release( Button & );
+
+ virtual LedState F7_press( Button & );
+ virtual LedState F7_release( Button & );
+
+ virtual LedState F8_press( Button & );
+ virtual LedState F8_release( Button & );
+
+ virtual LedState F9_press( Button & );
+ virtual LedState F9_release( Button & );
+
+ virtual LedState F10_press( Button & );
+ virtual LedState F10_release( Button & );
+
+ virtual LedState F11_press( Button & );
+ virtual LedState F11_release( Button & );
+
+ virtual LedState F12_press( Button & );
+ virtual LedState F12_release( Button & );
+
+ virtual LedState F13_press( Button & );
+ virtual LedState F13_release( Button & );
+
+ virtual LedState F14_press( Button & );
+ virtual LedState F14_release( Button & );
+
+ virtual LedState F15_press( Button & );
+ virtual LedState F15_release( Button & );
+
+ virtual LedState F16_press( Button & );
+ virtual LedState F16_release( Button & );
+
+ virtual LedState shift_press( Button & );
+ virtual LedState shift_release( Button & );
+
+ virtual LedState option_press( Button & );
+ virtual LedState option_release( Button & );
+
+ virtual LedState control_press( Button & );
+ virtual LedState control_release( Button & );
+
+ virtual LedState cmd_alt_press( Button & );
+ virtual LedState cmd_alt_release( Button & );
+
+ virtual LedState on_press( Button & );
+ virtual LedState on_release( Button & );
+
+ virtual LedState rec_ready_press( Button & );
+ virtual LedState rec_ready_release( Button & );
+
+ virtual LedState undo_press( Button & );
+ virtual LedState undo_release( Button & );
+
+ virtual LedState snapshot_press( Button & );
+ virtual LedState snapshot_release( Button & );
+
+ virtual LedState touch_press( Button & );
+ virtual LedState touch_release( Button & );
+
+ virtual LedState redo_press( Button & );
+ virtual LedState redo_release( Button & );
+
+ virtual LedState marker_press( Button & );
+ virtual LedState marker_release( Button & );
+
+ virtual LedState enter_press( Button & );
+ virtual LedState enter_release( Button & );
+
+ virtual LedState cancel_press( Button & );
+ virtual LedState cancel_release( Button & );
+
+ virtual LedState mixer_press( Button & );
+ virtual LedState mixer_release( Button & );
+
+ virtual LedState frm_left_press( Button & );
+ virtual LedState frm_left_release( Button & );
+
+ virtual LedState frm_right_press( Button & );
+ virtual LedState frm_right_release( Button & );
+
+ virtual LedState loop_press( Button & );
+ virtual LedState loop_release( Button & );
+
+ virtual LedState punch_in_press( Button & );
+ virtual LedState punch_in_release( Button & );
+
+ virtual LedState punch_out_press( Button & );
+ virtual LedState punch_out_release( Button & );
+
+ virtual LedState home_press( Button & );
+ virtual LedState home_release( Button & );
+
+ virtual LedState end_press( Button & );
+ virtual LedState end_release( Button & );
+
+ virtual LedState rewind_press( Button & );
+ virtual LedState rewind_release( Button & );
+
+ virtual LedState ffwd_press( Button & );
+ virtual LedState ffwd_release( Button & );
+
+ virtual LedState stop_press( Button & );
+ virtual LedState stop_release( Button & );
+
+ virtual LedState play_press( Button & );
+ virtual LedState play_release( Button & );
+
+ virtual LedState record_press( Button & );
+ virtual LedState record_release( Button & );
+
+ virtual LedState cursor_up_press( Button & );
+ virtual LedState cursor_up_release( Button & );
+
+ virtual LedState cursor_down_press( Button & );
+ virtual LedState cursor_down_release( Button & );
+
+ virtual LedState cursor_left_press( Button & );
+ virtual LedState cursor_left_release( Button & );
+
+ virtual LedState cursor_right_press( Button & );
+ virtual LedState cursor_right_release( Button & );
+
+ virtual LedState zoom_press( Button & );
+ virtual LedState zoom_release( Button & );
+
+ virtual LedState scrub_press( Button & );
+ virtual LedState scrub_release( Button & );
+
+ virtual LedState user_a_press( Button & );
+ virtual LedState user_a_release( Button & );
+
+ virtual LedState user_b_press( Button & );
+ virtual LedState user_b_release( Button & );
+
+ virtual LedState fader_touch_press( Button & );
+ virtual LedState fader_touch_release( Button & );
+
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_control_exception.h b/libs/surfaces/mackie/mackie_control_exception.h
new file mode 100644
index 0000000000..afe7016948
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_exception.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef mackie_control_exception_h
+#define mackie_control_exception_h
+
+#include
+
+namespace Mackie
+{
+
+class MackieControlException : public std::exception
+{
+public:
+ MackieControlException( const std::string & msg )
+ : _msg( msg )
+ {
+ }
+
+ virtual ~MackieControlException() throw () {}
+
+ const char * what() const throw ()
+ {
+ return _msg.c_str();
+ }
+
+private:
+ std::string _msg;
+};
+
+}
+
+#endif
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
new file mode 100644
index 0000000000..2d443ad711
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -0,0 +1,1293 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id: mackie_control_protocol.cc 1059 2006-11-02 12:27:49Z paul $
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#define __STDC_FORMAT_MACROS
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include "mackie_control_protocol.h"
+
+#include "midi_byte_array.h"
+#include "mackie_control_exception.h"
+#include "route_signal.h"
+#include "mackie_midi_builder.h"
+#include "surface_port.h"
+#include "surface.h"
+#include "bcf_surface.h"
+#include "mackie_surface.h"
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace Mackie;
+using namespace PBD;
+
+using boost::shared_ptr;
+
+#include "i18n.h"
+
+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 )
+ , connections_back( _connections )
+ , _surface( 0 )
+ , _ports_changed( false )
+ , pfd( 0 )
+ , nfds( 0 )
+{
+ cout << "MackieControlProtocol::MackieControlProtocol" << endl;
+ // 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;
+ close();
+}
+
+Mackie::Surface & MackieControlProtocol::surface()
+{
+ if ( _surface == 0 )
+ {
+ throw MackieControlException( "_surface is 0 in MackieControlProtocol::surface" );
+ }
+ return *_surface;
+}
+
+const Mackie::MackiePort & MackieControlProtocol::mcu_port() const
+{
+ return dynamic_cast( *_ports[0] );
+}
+
+Mackie::MackiePort & MackieControlProtocol::mcu_port()
+{
+ return dynamic_cast( *_ports[0] );
+}
+
+// go to the previous track.
+// Assume that get_sorted_routes().size() > route_table.size()
+void MackieControlProtocol::prev_track()
+{
+ if ( _current_initial_bank >= 1 )
+ {
+ session->set_dirty();
+ switch_banks( _current_initial_bank - 1 );
+ }
+}
+
+// go to the next track.
+// Assume that get_sorted_routes().size() > route_table.size()
+void MackieControlProtocol::next_track()
+{
+ Sorted sorted = get_sorted_routes();
+ if ( _current_initial_bank + route_table.size() < sorted.size() )
+ {
+ session->set_dirty();
+ switch_banks( _current_initial_bank + 1 );
+ }
+}
+
+void MackieControlProtocol::clear_route_signals()
+{
+ for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it )
+ {
+ delete *it;
+ }
+ route_signals.clear();
+}
+
+// return the port for a given id - 0 based
+// throws an exception if no port found
+MackiePort & MackieControlProtocol::port_for_id( uint32_t index )
+{
+ uint32_t current_max = 0;
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ current_max += (*it)->strips();
+ if ( index < current_max ) return **it;
+ }
+
+ // oops - no matching port
+ ostringstream os;
+ os << "No port for index " << index;
+ throw MackieControlException( os.str() );
+}
+
+// predicate for sort call in get_sorted_routes
+struct RouteByRemoteId
+{
+ bool operator () ( const shared_ptr & a, const shared_ptr & b ) const
+ {
+ return a->remote_control_id() < b->remote_control_id();
+ }
+
+ bool operator () ( const Route & a, const Route & b ) const
+ {
+ return a.remote_control_id() < b.remote_control_id();
+ }
+
+ bool operator () ( const Route * a, const Route * b ) const
+ {
+ return a->remote_control_id() < b->remote_control_id();
+ }
+};
+
+MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
+{
+ Sorted sorted;
+
+ // fetch all routes
+ boost::shared_ptr routes = session->get_routes();
+
+ // sort in remote_id order, and exclude master, control and hidden routes
+ for ( Session::RouteList::iterator it = routes->begin(); it != routes->end(); ++it )
+ {
+ Route & route = **it;
+ if ( route.active() && !route.master() && !route.hidden() && !route.control() )
+ {
+ sorted.push_back( *it );
+ }
+ }
+ sort( sorted.begin(), sorted.end(), RouteByRemoteId() );
+ return sorted;
+}
+
+void MackieControlProtocol::refresh_current_bank()
+{
+ switch_banks( _current_initial_bank );
+}
+
+void MackieControlProtocol::switch_banks( int initial )
+{
+ // DON'T prevent bank switch if initial == _current_initial_bank
+ // because then this method can't be used as a refresh
+
+ // sanity checking
+ Sorted sorted = get_sorted_routes();
+ int delta = sorted.size() - route_table.size();
+ if ( initial < 0 || ( delta > 0 && initial > delta ) )
+ {
+ cout << "not switching to " << initial << endl;
+ return;
+ }
+ _current_initial_bank = initial;
+
+ // first clear the signals from old routes
+ // taken care of by the RouteSignal destructors
+ clear_route_signals();
+
+ // now set the signals for new routes
+ if ( _current_initial_bank <= sorted.size() )
+ {
+ // fetch the bank start and end to switch to
+ 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;
+
+ // link routes to strips
+ uint32_t i = 0;
+ for ( ; it != end && it != sorted.end(); ++it, ++i )
+ {
+ boost::shared_ptr 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;
+ route_table[i] = route;
+ RouteSignal * rs = new RouteSignal( *route, *this, strip, port_for_id(i) );
+ route_signals.push_back( rs );
+ // update strip from route
+ rs->notify_all();
+ }
+
+ // create dead strips if there aren't enough routes to
+ // fill a bank
+ for ( ; i < route_table.size(); ++i )
+ {
+ Strip & strip = *surface().strips[i];
+ // send zero for this strip
+ port_for_id(i).write( builder.zero_strip( 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 ) );
+ }
+ }
+}
+
+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" ) );
+ }
+
+ // 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 ) );
+ }
+
+ // 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( control ), off ) );
+ }
+
+ // turn off global buttons and leds
+ // global buttons are only ever on mcu_port, so we don't have
+ // to figure out which port.
+ for ( Surface::Controls::iterator it = surface().controls.begin(); it != surface().controls.end(); ++it )
+ {
+ Control & control = **it;
+ if ( !control.group().is_strip() && control.accepts_feedback() )
+ {
+ mcu_port().write( builder.zero_control( control ) );
+ }
+ }
+}
+
+int MackieControlProtocol::set_active (bool yn)
+{
+ if ( yn != _active )
+ {
+ try
+ {
+ // the reason for the locking and unlocking is that
+ // glibmm can't do a condition wait on a RecMutex
+ if ( yn )
+ {
+ // TODO what happens if this fails half way?
+ cout << "set_active true" << endl;
+
+ // create MackiePorts
+ {
+ Glib::Mutex::Lock lock( update_mutex );
+ create_ports();
+ }
+
+ // wait until poll thread is running, with ports to poll
+ // the mutex is only there because conditions require a mutex
+ {
+ Glib::Mutex::Lock lock( update_mutex );
+ while ( nfds == 0 ) update_cond.wait( update_mutex );
+ }
+
+ // now initialise MackiePorts - ie exchange sysex messages
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ (*it)->open();
+ }
+
+ // wait until all ports are active
+ // TODO a more sophisticate approach would
+ // allow things to start up with only an MCU, even if
+ // extenders were specified but not responding.
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ (*it)->wait_for_init();
+ }
+
+ // create surface object. This depends on the ports being
+ // correctly initialised
+ initialize_surface();
+ connect_session_signals();
+
+ // yeehah!
+ _active = true;
+
+ // send current control positions to surface
+ // must come after _active = true otherwise it won't run
+ update_surface();
+ }
+ else
+ {
+ cout << "set_active false" << endl;
+ close();
+ _active = false;
+ }
+ }
+ catch( exception & e )
+ {
+ cout << "set_active to false because " << e.what() << endl;
+ _active = false;
+ throw;
+ }
+ }
+
+ return 0;
+}
+
+bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState bs, boost::shared_ptr route )
+{
+ bool state = false;
+
+ if ( bs == press )
+ {
+ if ( control.name() == "recenable" )
+ {
+ state = !route->record_enabled();
+ route->set_record_enable( state, this );
+ }
+ else if ( control.name() == "mute" )
+ {
+ state = !route->muted();
+ route->set_mute( state, this );
+ }
+ else if ( control.name() == "solo" )
+ {
+ state = !route->soloed();
+ route->set_solo( state, this );
+ }
+ else if ( control.name() == "select" )
+ {
+ // TODO make the track selected. Whatever that means.
+ //state = default_button_press( dynamic_cast