diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2007-06-28 19:35:48 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2007-06-28 19:35:48 +0000 |
commit | f95aa76f4a16a3f2bfd427b1e454023c3b886e5f (patch) | |
tree | f595f3b5b0fcae6a52e6268d1c714d4d5674d6b5 /libs/surfaces/powermate/powermate.cc | |
parent | 39f5c0ad562349404bf3f6c4ddae94fef17f1295 (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.cc | 235 |
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; +} + + |