236 lines
4.5 KiB
C++
236 lines
4.5 KiB
C++
|
/*
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|