summaryrefslogtreecommitdiff
path: root/libs/surfaces/powermate/powermate.cc
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-06-28 19:35:48 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-06-28 19:35:48 +0000
commitf95aa76f4a16a3f2bfd427b1e454023c3b886e5f (patch)
treef595f3b5b0fcae6a52e6268d1c714d4d5674d6b5 /libs/surfaces/powermate/powermate.cc
parent39f5c0ad562349404bf3f6c4ddae94fef17f1295 (diff)
add basic support for the griffin powermate (a control surface) (from ben loftis)
git-svn-id: svn://localhost/ardour2/trunk@2078 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/surfaces/powermate/powermate.cc')
-rw-r--r--libs/surfaces/powermate/powermate.cc235
1 files changed, 235 insertions, 0 deletions
diff --git a/libs/surfaces/powermate/powermate.cc b/libs/surfaces/powermate/powermate.cc
new file mode 100644
index 0000000000..139313f3f8
--- /dev/null
+++ b/libs/surfaces/powermate/powermate.cc
@@ -0,0 +1,235 @@
+/*
+ powermate.cc
+ Ben Loftis
+ Created: 03/26/07 20:07:56
+*/
+
+
+#include <linux/input.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <i18n.h>
+#include <pbd/xml++.h>
+
+#include "powermate.h"
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+
+#define NUM_VALID_PREFIXES 2
+
+static const char *valid_prefix[NUM_VALID_PREFIXES] = {
+ "Griffin PowerMate",
+ "Griffin SoundKnob"
+};
+
+#define NUM_EVENT_DEVICES 16
+
+int open_powermate(const char *dev, int mode)
+{
+ int fd = open(dev, mode);
+ int i;
+ char name[255];
+
+ if(fd < 0){
+ fprintf(stderr, "Unable to open \"%s\": %s\n", dev, strerror(errno));
+ return -1;
+ }
+
+ if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0){
+ fprintf(stderr, "\"%s\": EVIOCGNAME failed: %s\n", dev, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ // it's the correct device if the prefix matches what we expect it to be:
+ for(i=0; i<NUM_VALID_PREFIXES; i++)
+ if(!strncasecmp(name, valid_prefix[i], strlen(valid_prefix[i])))
+ return fd;
+
+ close(fd);
+ return -1;
+}
+
+int find_powermate(int mode)
+{
+ char devname[256];
+ int i, r;
+
+ for(i=0; i<NUM_EVENT_DEVICES; i++){
+ sprintf(devname, "/dev/input/event%d", i);
+ r = open_powermate(devname, mode);
+ if(r >= 0)
+ return r;
+ }
+
+ return -1;
+}
+
+PowermateControlProtocol::PowermateControlProtocol (Session& s)
+ : ControlProtocol (s, "powermate")
+{
+}
+
+PowermateControlProtocol::~PowermateControlProtocol ()
+{
+ set_active (false);
+}
+
+bool
+PowermateControlProtocol::probe ()
+{
+ int port = find_powermate( O_RDONLY );
+
+ if (port < 0) {
+ printf ("powermate: Opening of powermate failed - %s\n", strerror(errno));
+ close (port);
+ return false;
+ }
+
+ close (port);
+ return true;
+}
+
+int
+PowermateControlProtocol::set_active (bool inActivate)
+{
+ if (inActivate != _active) {
+
+ if (inActivate) {
+
+ mPort = find_powermate(O_RDONLY);
+
+ if ( mPort < 0 ) {
+ return -1;
+ }
+
+ if (pthread_create (&mThread, 0, SerialThreadEntry, this) == 0) {
+ _active = true;
+ } else {
+ return -1;
+ }
+
+ printf("Powermate Control Protocol activated\n");
+
+ } else {
+ pthread_cancel (mThread);
+ close (mPort);
+ _active = false;
+ printf("Powermate Control Protocol deactivated\n");
+ }
+ }
+
+ return 0;
+}
+
+XMLNode&
+PowermateControlProtocol::get_state ()
+{
+ XMLNode* node = new XMLNode (X_("Protocol"));
+ node->add_property (X_("name"), _name);
+ return *node;
+}
+
+int
+PowermateControlProtocol::set_state (const XMLNode& node)
+{
+ return 0;
+}
+
+
+void*
+PowermateControlProtocol::SerialThreadEntry (void* arg)
+{
+ return static_cast<PowermateControlProtocol*>(arg)->SerialThread ();
+}
+
+#define BUFFER_SIZE 32
+
+bool held = false;
+bool skippingMarkers = false;
+
+void
+PowermateControlProtocol::ProcessEvent(struct input_event *ev)
+{
+#ifdef VERBOSE
+ fprintf(stderr, "type=0x%04x, code=0x%04x, value=%d\n",
+ ev->type, ev->code, (int)ev->value);
+#endif
+
+ switch(ev->type){
+ case EV_MSC:
+ printf("The LED pulse settings were changed; code=0x%04x, value=0x%08x\n", ev->code, ev->value);
+ break;
+ case EV_REL:
+ if(ev->code != REL_DIAL)
+ fprintf(stderr, "Warning: unexpected rotation event; ev->code = 0x%04x\n", ev->code);
+ else{
+ if (held) {
+ //click and hold to skip forward and back by markers
+ skippingMarkers = true;;
+ if (ev->value > 0)
+ next_marker();
+ else
+ prev_marker();
+ } else {
+ //scale the range so that we can go from +/-8x within 180 degrees, with less precision at the higher speeds
+ float speed = get_transport_speed();
+ speed += (float)ev->value * 0.05;
+ if (speed > 1.5 || speed < -1.5 )
+ speed += ev->value;
+ set_transport_speed( speed );
+ }
+ }
+ break;
+ case EV_KEY:
+ if(ev->code != BTN_0)
+ fprintf(stderr, "Warning: unexpected key event; ev->code = 0x%04x\n", ev->code);
+ else
+ if (ev->value)
+ held = true;
+ else {
+ held = false;
+ if (skippingMarkers) {
+ skippingMarkers = false;
+ } else {
+ if (get_transport_speed() == 0.0) {
+ set_transport_speed(1.0);
+ } else {
+ set_transport_speed(0.0);
+ }
+ }
+ }
+ break;
+ }
+
+ fflush(stdout);
+}
+
+void*
+PowermateControlProtocol::SerialThread ()
+{
+ struct input_event ibuffer[BUFFER_SIZE];
+ int r, events, i;
+
+ while(1){
+ r = read(mPort, ibuffer, sizeof(struct input_event) * BUFFER_SIZE);
+ if( r > 0 ){
+ events = r / sizeof(struct input_event);
+ for(i=0; i<events; i++)
+ ProcessEvent(&ibuffer[i]);
+ }else{
+ fprintf(stderr, "read() failed: %s\n", strerror(errno));
+ return (void*) 0;
+ }
+ }
+
+ return (void*) 0;
+}
+
+