Hi guys,
I had been meaning to try interfacing my graphics tablet with supercollider for some time: in my mind, it could be an excellent expressive tool for controlling different synthesis parameters in parallel.
I have taken some first steps in this direction and am pleased to share them with you.
My tablet is a Wacom CTE-640 (user manual link here);
Let me preface this by saying that I have not delved deeply into the low-level workings of HID devices, I have limited myself to a relatively superficial analysis in order to be able to capture data from the tablet and apply it in a short time.
First of all I have to find the device:
HID.findAvailable;
in my case the Wacom tablet is on the first place:
~myhid = HID.openPath( "/dev/hidraw0");
evaluating the line below I’ve found my tablet has 16 elements:
~myhid.postElements;
but I was able to figure out only some of these.
So I defined some HIDdef
for the working elements (description below):
(
// Element 7 on my tablet seems to correspond to a series of momentary events linked to the movement of the pencil/eraser, its buttons and the two tablet buttons
HIDdef.element( \penDistanceAndButtons, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
case
{rawValue == 0} { "pen away".postln; }
// PEN STUFF
{rawValue == 18} { "far w right click".postln; }
{rawValue == 146} { "near w right click".postln; }
{rawValue == 147} { "touch w right click".postln; }
{rawValue == 20} { "far w double click".postln; }
{rawValue == 148} { "near w double click".postln; }
{rawValue == 149} { "touch w double click".postln; }
{rawValue == 16} { "far".postln; }
{rawValue == 144} { "near".postln; }
{rawValue == 145} { "touch".postln; }
// ERASER STUFF
{rawValue == 50} { "eraser far w right click".postln; }
{rawValue == 178} { "eraser near w right click".postln; }
{rawValue == 179} { "eraser touch w right click".postln; }
{rawValue == 52} { "eraser far w double click".postln; }
{rawValue == 180} { "eraser near w double click".postln; }
{rawValue == 181} { "eraser touch w double click".postln; }
{rawValue == 48} { "eraser near".postln; }
{rawValue == 176} { "eraser almost touch".postln; }
{rawValue == 177} { "eraser touch".postln; }
}, 7);
)
(
// element 8 appears to continuously return (even if the pencil is stationary) a byte (value between 0 and 255) that cycles between minimum and maximum as the pencil/eraser slides horizontally across the tablet.
HIDdef.element( \orizontal_ciclycValue, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
rawValue.postln;
}, 8);
)
(
// element 9 returns a value only if the pencil/eraser moves. This is an absolute integer value varying, at least in my case, between 0 and 65, which represents the horizontal position.
HIDdef.element( \orizontal_value, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
postf("X value (0-65) is: %\n", rawValue);
}, 9);
)
(
// element 10 - like element 8 - appears to continuously return (even if the pencil is stationary) a byte (value between 0 and 255) that cycles between minimum and maximum as the pencil/eraser slides vertically across the tablet.
HIDdef.element( \vertical_cyclicValue, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
rawValue.postln;
}, 10);
)
(
// element 11 returns a value only if the pencil/eraser moves. This is an absolute integer value varying, at least in my case, between 0 and 47, which represents the vertical position.
HIDdef.element( \vertical_value, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
postf("Y value (0-47) is: %\n", rawValue);
}, 11);
)
(
// it seems to me that item 12 has something to do with the pressure level of the pencil on the tablet. In my case it is expressed as bytes (values from 0 and 255) and the value seems to cycle twice between minimum and maximum as the pressure increases or decreases. I have no idea why this quantity is represented in this way. If you can think of a way to map it more sensibly, let me know :)
HIDdef.element( \pressure_cyclicValue, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
postf("pressure value is: %\n", rawValue);
}, 12);
)
(
// Element 13 shows some of the tablet's functions in the form of flags. Several functionalities used simultaneously can be detected by doing some bitwise operations.
// pen placed adds 1; 0000 0001
// forth scroll adds: 8; 0000 1000
// left button adds: 64; 0100 0000
// right button adds: 128; 1000 0000
// back scroll adds: 56; 0011 1000
HIDdef.element( \penEraserTouch_2, {
|value, rawValue, usage, page, elid, ele, devid, device, key|
//[rawValue, value, usage, page, elid, ele, devid, device, key].postln;
//rawValue.asBinaryDigits.postln;
postln("");
if( rawValue.bitAnd(56) == 56,
{ "scroll down".postln },
{
if( rawValue.bitAnd(8) == 8, { "scroll up".postln });
}
);
if( rawValue.bitTest(0), {"pen placed".postln});
if( rawValue.bitTest(6), {"left button".postln});
if( rawValue.bitTest(7), {"right button".postln});
}, 13);
)
That is all I have been able to understand so far.
I hope it will be useful and if you understand anything more, please share it 