/* powermate.cc Ben Loftis Created: 03/26/07 20:07:56 */ #include #include #include #include #include #include #include #include "pbd/pthread_utils.h" #include "pbd/xml++.h" #include "pbd/error.h" #include "powermate.h" #include "i18n.h" using namespace ARDOUR; using namespace std; using namespace sigc; using namespace PBD; #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) { if (!Glib::file_test (dev, Glib::FILE_TEST_EXISTS)) { return -1; } int fd = open(dev, mode); int i; char name[255]; if (fd < 0) { if (errno != EACCES) { error << string_compose ("Unable to open \"%1\": %2", dev, strerror(errno)) << endmsg; } return -1; } /* placate valgrind */ name[0] = '\0'; if (ioctl (fd, EVIOCGNAME (sizeof(name)), name) < 0) { error << string_compose ("\"%1\": EVIOCGNAME failed: %2", dev, strerror(errno)) << endmsg; 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) { if (errno == ENOENT) { info << "Powermate device not found; perhaps you have no powermate connected" << endmsg; } else { printf ("powermate: Opening of powermate failed - %s\n", strerror(errno)); } 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_and_store ("Powermate", &mThread, 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*/, int /*version*/) { return 0; } void* PowermateControlProtocol::SerialThreadEntry (void* arg) { static_cast(arg)->register_thread ("Powermate"); return static_cast(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