Graphic tablet input

I was wondering if there is any way of using a graphic tablet (wacom intuos pro smth) as input device in Supercollider. Seems like there once have been functions for that in something called cocoa gui (which has been mac exclusive and hasn’t been in sc for a couple of years). So I was wondering: is there some way to not only use X and Y coordinates (which just works via MouseX/Y) but also the pressure/tilt?

Also for the unlikely case that someone has some expertise on that topic: Do you accidently know if it is possible to configure a wacom tablet so that touchinput is treated like peninput is (meaning it is not continuously sliding, but instead the surface of the tablet is precisely mapped to the display, meaning that if you lift your finger and lets say put it down again in the upper left cornor the mouse jumps to the upper left cornor of the screen)

Thanks a lot in advance!

PS: I’m on Supercollider 3.11 currently

WACOM tablets should show up as HID devices, at least on Mac. Take a look at the “Working with HID” help file to get started - to be honest, getting this set up can require a bit of investigation, but it is possible! If you see your WACOM when you do HID.findAvailable / HID.postAvailable then you should be on the right track!

If you get a basic WACOM setup working, please post the code so others can see how you did it.

If the stock HID interface in SC is not doing the job, you can try OSCulator. It supports Wacoms, not sure for your exact model. It costs 20 bucks. Eli Fieldsteel has a nice tuto on youtube that shows how to use it with Wiimote, should be similar with Wacom.

Thanks a lot scztt & Benu. I’ll first try to get the input running using the stock HID device. I’m going to pot an update as soon as I make some progress. I’m rather a novice in SC, so I might ask some questions too if I bump into something I can’t figure out for my self.

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 :slight_smile: