mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-15 19:16:40 +01:00
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
This commit is contained in:
parent
39f5c0ad56
commit
f95aa76f4a
15 changed files with 438 additions and 16 deletions
21
libs/surfaces/powermate/README
Normal file
21
libs/surfaces/powermate/README
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
This module works with the Griffin Powermate and allows some basic transport control.
|
||||
|
||||
It autodetects the Powermate on any input device of the form "/dev/input/event*". This means you must have the powermate module in your kernel. It works out-of-the-box with 64Studio and presumably lots of other modern distributions.
|
||||
|
||||
Turning the wheel left and right will act as a "Shuttle" wheel, adjusting playback speed up and down
|
||||
Pushing the knob will switch between play and stop
|
||||
Pushing the knob while turning will jump to the next or previous markers
|
||||
|
||||
|
||||
In order for the powermate to work, you have to have permission to open the input device for reading.
|
||||
In debian, I changed /etc/udev/rules.d/0_permissions.rules to have the line:
|
||||
KERNEL=="event[0-9]*", MODE="0666"
|
||||
but there are other ways to achieve this
|
||||
|
||||
|
||||
Feedback, tweaks, bug fixes and feature ideas are encouraged
|
||||
|
||||
-Ben Loftis, ben@benloftis.com
|
||||
|
||||
|
||||
57
libs/surfaces/powermate/SConscript
Normal file
57
libs/surfaces/powermate/SConscript
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# -*- python -*-
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
Import('env final_prefix install_prefix final_config_prefix libraries i18n')
|
||||
|
||||
powermate = env.Copy()
|
||||
|
||||
#
|
||||
# this defines the version number of powermate
|
||||
#
|
||||
|
||||
domain = 'ardour_powermate'
|
||||
|
||||
powermate.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
|
||||
powermate.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
|
||||
powermate.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
|
||||
powermate.Append(PACKAGE = domain)
|
||||
powermate.Append(POTFILE = domain + '.pot')
|
||||
|
||||
powermate_files=Split("""
|
||||
interface.cc
|
||||
powermate.cc
|
||||
""")
|
||||
|
||||
powermate.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
|
||||
powermate.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
|
||||
powermate.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
|
||||
powermate.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
|
||||
|
||||
powermate.Merge ([
|
||||
libraries['ardour'],
|
||||
libraries['ardour_cp'],
|
||||
libraries['sigc2'],
|
||||
libraries['pbd'],
|
||||
libraries['midi++2'],
|
||||
libraries['xml'],
|
||||
libraries['usb'],
|
||||
libraries['glib2'],
|
||||
libraries['glibmm2']
|
||||
])
|
||||
|
||||
libardour_powermate = powermate.SharedLibrary('ardour_powermate', powermate_files)
|
||||
|
||||
Default(libardour_powermate)
|
||||
|
||||
if env['NLS']:
|
||||
i18n (powermate, powermate_files, env)
|
||||
|
||||
env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2/surfaces'), libardour_powermate))
|
||||
|
||||
env.Alias('tarball', env.Distribute (env['DISTTREE'],
|
||||
[ 'SConscript' ] +
|
||||
powermate_files +
|
||||
glob.glob('po/*.po') + glob.glob('*.h')))
|
||||
57
libs/surfaces/powermate/interface.cc
Normal file
57
libs/surfaces/powermate/interface.cc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
Ardour9pin interface file
|
||||
Ben Loftis
|
||||
Created: 05/18/06 11:07:56
|
||||
Copyright Harrison Audio, LLC, 2007
|
||||
*/
|
||||
|
||||
#include "powermate.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
ControlProtocol*
|
||||
new_powermate_protocol (ControlProtocolDescriptor* descriptor, Session* s)
|
||||
{
|
||||
PowermateControlProtocol* pcp = new PowermateControlProtocol (*s);
|
||||
|
||||
if (pcp->set_active (true)) {
|
||||
delete pcp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return pcp;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
delete_powermate_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
|
||||
{
|
||||
delete cp;
|
||||
}
|
||||
|
||||
bool
|
||||
probe_powermate_protocol (ControlProtocolDescriptor* descriptor)
|
||||
{
|
||||
return PowermateControlProtocol::probe ();
|
||||
}
|
||||
|
||||
static ControlProtocolDescriptor powermate_descriptor = {
|
||||
name : "powermate",
|
||||
id : "uri://ardour.org/ardour/powermate:0",
|
||||
ptr : 0,
|
||||
module : 0,
|
||||
mandatory : 0,
|
||||
supports_feedback : false,
|
||||
probe : probe_powermate_protocol,
|
||||
initialize : new_powermate_protocol,
|
||||
destroy : delete_powermate_protocol
|
||||
};
|
||||
|
||||
|
||||
extern "C" {
|
||||
ControlProtocolDescriptor*
|
||||
protocol_descriptor () {
|
||||
return &powermate_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
libs/surfaces/powermate/interface.os
Normal file
BIN
libs/surfaces/powermate/interface.os
Normal file
Binary file not shown.
BIN
libs/surfaces/powermate/libardour_powermate.so
Executable file
BIN
libs/surfaces/powermate/libardour_powermate.so
Executable file
Binary file not shown.
235
libs/surfaces/powermate/powermate.cc
Normal file
235
libs/surfaces/powermate/powermate.cc
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
34
libs/surfaces/powermate/powermate.h
Normal file
34
libs/surfaces/powermate/powermate.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef ardour_powermate_h
|
||||
#define ardour_powermate_h
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "control_protocol/control_protocol.h"
|
||||
|
||||
class PowermateControlProtocol : public ARDOUR::ControlProtocol
|
||||
{
|
||||
public:
|
||||
PowermateControlProtocol (ARDOUR::Session&);
|
||||
virtual ~PowermateControlProtocol();
|
||||
|
||||
int set_active (bool yn);
|
||||
static bool probe ();
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&);
|
||||
|
||||
private:
|
||||
|
||||
static void* SerialThreadEntry (void* arg);
|
||||
void* SerialThread ();
|
||||
|
||||
void ProcessEvent(struct input_event *ev);
|
||||
|
||||
int mPort;
|
||||
pthread_t mThread;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
BIN
libs/surfaces/powermate/powermate.os
Normal file
BIN
libs/surfaces/powermate/powermate.os
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue