Use a gamepad to control Supercollider.
HIDDeviceService

A Service that provides access to Human Interface Devices like joysticks and gamepads.

This service was mainly designed to use gamepads as control input. The name is derived from the mac osx specifications. 
The HIDDeviceService handles all the primitive calls. HIDDevice only stores information about a device and holds an array of HIDElements, which store information about the controllers of the device.

A HIDDevice's information consists of: 
•	the manufacturer, the product, the usage, the vendorID, the productID and the locID.
•	The last three are used to identify the device. The vendorID and the productID are static for each device, the locID depends on the (usb) port the device is connected to.

A HIDDeviceElement's information consists out of: 
•	the type, the usage, the cookie, the minimum and the maximum value.
•	the cookie is a number that can be used to identify an element of a device.
	
There are two ways of getting values from the device: One is to poll a value, the other one is to start an eventloop that pushes every new value into the language and calls an action (like MIDIIn).

To set up an eventloop follow these steps:
	1. initialize the service by calling:
	
		HIDDeviceService.buildDeviceList;
		
	2. now the information about the devices can be found:
		
		(
		HIDDeviceService.devices.do({arg dev;
			[dev.manufacturer, dev.product, dev.vendorID, dev.productID, dev.locID].postln;
			dev.elements.do({arg ele;
				[ele.type, ele.usage, ele.cookie, ele.min, ele.max].postln;
			});
		});
		)
	
	3. the device needs to be queued, that means that the eventloop actually uses this device to push values. 
		
		HIDDeviceService.devices.at(0).queueDevice;
	
	4. set an action that is called by the incoming events. In addition to the value the events also deliver the productID, the vendorID and the locID of the device and the cookie of the element.
		
		(
		HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
				[productID, vendorID, locID, cookie, val].postln;
		});
		)
		
	5. start the eventloop:
		
		HIDDeviceService.runEventLoop;
		
	6. stop the eventloop:
		
		HIDDeviceService.stopEventLoop;
		
// For instance, evaluate the above lines, and then...	
// This use key values to control the impulses for TGrains...

// Load the buffer (10)
s.sendMsg(\b_allocRead, 10, "sounds/a11wlk01.wav");

(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
	var mykey;
//	[doc, key, modifiers].postln;
//	mykey = num;
	[cookie, val].postln;
	if(cookie == 18,
	{
		{EnvGen.kr(Env.perc([0.05,0.001,0.01].choose, [0.1,0.2,0.01].choose, 1, -4), doneAction:2) * SinOsc.ar(val*10, 0, 0.5)}.play;
		"bong".postln;
	});
	
	if(cookie == 19,
	{
		{EnvGen.kr(Env.perc([0.05,0.001,0.1].choose, [0.1,0.2,0.1].choose, 1, -4), doneAction:2) * TGrains.ar(2, Impulse.ar(val), 10, Dseq([10, 1, 1, 0.5, 0.5, 0.2, 0.1], inf), val, 0.04, Dseq([-1, 1], inf), 0.1, 2);}.play;
		"apollo".postln;
	});
})
)

// Some more HI stuff...

buildDeviceList(usagePage, usage)

It is also possible to search for devices in other usage pages. (look in the class file)
the default is: page: GenericDesktop usage: Joystick. if a nil is passed in all devices are listed.

//HIDDeviceServis by jan trutzschler v. falkenstein

deviceSpecs
	you can add to the classvar deviceSpecs the specs of your device.
	the key used has to be the product name derived from the device info.

here is a collection of specs:

//wingman
(
HIDDeviceService.deviceSpecs.put('Logitech RumblePad 2 USB', 
			IdentityDictionary[
				\l -> 6, \slider -> 12, \b -> 1,
				\y -> 4, \hat -> 13, \r -> 7,
				\yy -> 11, \xx -> 10, \x -> 3,
				\a -> 0, \mode -> 19, \c -> 2, 
				\z -> 5, \s -> 8
			])
)

//wingman - a little more logically displayed
(
HIDDeviceService.deviceSpecs.put('Logitech RumblePad 2 USB', 
			IdentityDictionary[
				\a -> 0, \b-> 1, \c-> 2,
				\x-> 3, \y-> 4, \z-> 5,
				\l-> 6, //front left
				\r-> 7, //front right
				\s-> 8, 
				\mode-> 19,
				\xx-> 10,		
				\yy-> 11,		
				\slider-> 12,
				\hat-> 13
			])
)

//cyborg
(
HIDDeviceService.deviceSpecs.put(\cyborg,  //not the right product name yet, so this doesn't work.
			IdentityDictionary[
				\trig -> 0, \a-> 1, \b -> 2, \c -> 3,
				\f1-> 4, \f2-> 5, \f3-> 6, \f4 -> 7,
				\l -> 8, \r -> 9, // arrow buttons
				\hu -> 10, \hl -> 11, \hr -> 12, \hd -> 13, // hat positions
				\x -> 14, \y -> 15, \z -> 16, // axes
				\slider-> 17,
				\hat-> 18
			]);
)

// Another example

1. initialize the service by calling:
	
HIDDeviceService.buildDeviceList;
		
2. now the information about the devices can be found:
		
(
HIDDeviceService.devices.do({arg dev;
	[dev.manufacturer, dev.product, dev.vendorID, dev.productID, dev.locID].postln;
	dev.elements.do({arg ele;
		[ele.type, ele.usage, ele.cookie, ele.min, ele.max].postln;
	});
});
)

(
HIDDeviceService.devices.do({arg dev;
	[dev.manufacturer, dev.product, dev.vendorID, dev.productID, dev.locID].postln;
	dev.elements.do({arg ele;
		[ele.type, ele.usage, ele.cookie, ele.min, ele.max].postln;

	});
	dev.elements.max.postln;
});
)

	
3. the device needs to be queued, that means that the eventloop actually uses this device to push values. 
		
HIDDeviceService.devices.at(0).queueDevice;
	
4. set an action that is called by the incoming events. In addition to the value the events also deliver the productID, the vendorID and the locID of the device and the cookie of the element.
		
(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
		[productID, vendorID, locID, cookie, val].postln;
});
)

// This is a more modest amount of information, but probably a little more useful:

(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
		[cookie, val].postln;
});
)

(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
		var myval;
		[cookie, val].postln;
		myval = val;
		
		// You can try any of the following, but be careful as the first one will simply make more and more synths...  You'll need to comment out those you don't want and remove the comment markings from those you don't...  You might also want to check out 'doneAction' settings (in the help files for line, env, etc.)...
		
		// { SinOsc.ar(([val]+400), 0, 0.5) }.play;
		{ SinOsc.ar(([val]+400), 0, XLine.kr(1.0, 0.001, 0.1, doneAction:12)) }.play; 
		// {EnvGen.kr(Env.perc(0.1, 0.1, 1, -4), doneAction:2) * SinOsc.ar(myval*4.0, 0, 0.5)}.play;
});
)

// Controller stuff.  A lot of this is still being processed and doesn't work, but you may find some parts useful to browse.

// start the eventloop:
HIDDeviceService.runEventLoop;
		
// stop the eventloop:
HIDDeviceService.stopEventLoop;

// poll the device
(
HIDDeviceService.buildDeviceList;
d = HIDDeviceService.devices.at(0);
e = d.elements;
e[1].name.postln;
t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		val = d.elements(i);
		// e[4].postln;
		if(val != lastval, {val = val.postln});
		});
	});
t.play;
)

// poll the device
(
HIDDeviceService.buildDeviceList;
d = HIDDeviceService.devices.at(0);
e = d.elements;

t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		// val = d.elements(i);
		e[1].postln;
		// if(val != lastval, {val = val.postln});
		})
	});
t.play;
)

// poll the device
(
HIDDeviceService.buildDeviceList;
d = HIDDeviceService.devices.at(0);

t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		val = d.getValue(i);
		if(val != lastval, {val = val.postln});
		})
	});
t.play;

)

HIDDeviceService.browse;

// poll the device
(
HIDDeviceService.buildDeviceList;
HIDDeviceService.devices.at(0).queueDevice;
d = HIDDeviceService.devices.at(0);
d.postln;

t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		val = HIDDeviceService.devices.at(0).getValue(i);
		// d(i).postln;
		if(val != lastval, {val = val.postln});
		val.postln;
		})
	});
t.play;

)

HIDDeviceService.action;

{ SinOsc.ar(HIDDeviceService.val, 0, 0.5) }.play;

MidiIn

examples:
// create
(
var c, d;
c = HIDResponder({|vend,prod,id,b,c| ("1st dev: " ++[vend,prod,id,b,c]).postln}, id:0) // 1st device
d = HIDResponder({|a,b,c,d,e| ("2nd dev: " ++ [a,b,c,d,e]).postln},id:1) // second device
d.remove;
)

// HIDDeviceResponder must be inited to get deviceNames
~name = c.deviceNames[0]
d = HIDResponder({|a,b,c,d,e| ("1st dev: " ++ [a,b,c,d,e]).postln},
id:~name, b:4)

c.remove
d.remove

c = HIDResponder({|a,b,c,d,e| ("keybd: " ++ [a,b,c,d,e]).postln},
id:\Keyboard)
c.devices
c.deviceNames
c.deviceName
c.deviceID

~mouse = c.devices[\Trackpad] // tested on a powerbook...
~kbd = c.devices[\Keyboard]

e = HIDResponder({|a,b,c,d,e| ("mouse: " ++ [a,b,c,d,e]).postln}, nil,
id:~mouse)
e.remove
f = HIDResponder({|a,b,c,d,e| ("keyboard: " ++ [a,b,c,d,e]).postln},
nil, id:~kbd)
f.remove

e.function.asCompileString

HIDResponder.removeAll

(
HIDDeviceService.deviceSpecs.put('Logitech RumblePad 2 USB', 
			IdentityDictionary[
				\l -> 6, \slider -> 12, \b -> 1,
				\y -> 4, \hat -> 13, \r -> 7,
				\yy -> 11, \xx -> 10, \x -> 3,
				\a -> 0, \mode -> 19, \c -> 2, 
				\z -> 5, \s -> 8
			])
)

(
HIDDeviceService.deviceSpecs.put('Rumble', 
			IdentityDictionary[
				\l -> 6, \slider -> 12, \b -> 1,
				\y -> 4, \hat -> 13, \r -> 7,
				\yy -> 11, \xx -> 10, \x -> 3,
				\a -> 0, \mode -> 19, \c -> 2, 
				\z -> 5, \s -> 8
			])
)

// poll the device
(
HIDDeviceService.buildDeviceList;
HIDDeviceService.devices.at(0).queueDevice;
d = HIDDeviceService.devices.at(0);
d.postln;

t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		val = HIDDeviceService.devices.at(0).getValue(i);
		// d(i).postln;
		if(val != lastval, {val = val.postln});
		val.postln;
		})
	});
t.play;

)

HIDDeviceService.action;

{ SinOsc.ar(HIDDeviceService.val, 0, 0.5) }.play;

MidiIn

examples:
// create
(
var c, d;
c = HIDResponder({|vend,prod,id,b,c| ("1st dev: " ++[vend,prod,id,b,c]).postln}, id:0) // 1st device
d = HIDResponder({|a,b,c,d,e| ("2nd dev: " ++ [a,b,c,d,e]).postln},id:1) // second device
d.remove;
)

// HIDDeviceResponder must be inited to get deviceNames
~name = c.deviceNames[0]
d = HIDResponder({|a,b,c,d,e| ("1st dev: " ++ [a,b,c,d,e]).postln},
id:~name, b:4)

c.remove
d.remove

c = HIDResponder({|a,b,c,d,e| ("keybd: " ++ [a,b,c,d,e]).postln},
id:\Keyboard)
c.devices
c.deviceNames
c.deviceName
c.deviceID

~mouse = c.devices[\Trackpad] // tested on a powerbook...
~kbd = c.devices[\Keyboard]

e = HIDResponder({|a,b,c,d,e| ("mouse: " ++ [a,b,c,d,e]).postln}, nil,
id:~mouse)
e.remove
f = HIDResponder({|a,b,c,d,e| ("keyboard: " ++ [a,b,c,d,e]).postln},
nil, id:~kbd)
f.remove

e.function.asCompileString

HIDResponder.removeAll

(
HIDDeviceService.deviceSpecs.put('Logitech RumblePad 2 USB', 
			IdentityDictionary[
				\l -> 6, \slider -> 12, \b -> 1,
				\y -> 4, \hat -> 13, \r -> 7,
				\yy -> 11, \xx -> 10, \x -> 3,
				\a -> 0, \mode -> 19, \c -> 2, 
				\z -> 5, \s -> 8
			])
)

(
HIDDeviceService.deviceSpecs.put('Rumble', 
			IdentityDictionary[
				\l -> 6, \slider -> 12, \b -> 1,
				\y -> 4, \hat -> 13, \r -> 7,
				\yy -> 11, \xx -> 10, \x -> 3,
				\a -> 0, \mode -> 19, \c -> 2, 
				\z -> 5, \s -> 8
			])
)

// Controller

1. initialize the service by calling:
	
HIDDeviceService.buildDeviceList;
		
2. now the information about the devices can be found:
		
(
HIDDeviceService.devices.do({arg dev;
	[dev.manufacturer, dev.product, dev.vendorID, dev.productID, dev.locID].postln;
	dev.elements.do({arg ele;
		[ele.type, ele.usage, ele.cookie, ele.min, ele.max].postln;
	});
});
)

(
HIDDeviceService.devices.do({arg dev;
	[dev.manufacturer, dev.product, dev.vendorID, dev.productID, dev.locID].postln;
	dev.elements.do({arg ele;
		[ele.type, ele.usage, ele.cookie, ele.min, ele.max].postln;

	});
	dev.elements.max.postln;
});
)

	
3. the device needs to be queued, that means that the eventloop actually uses this device to push values. 
		
HIDDeviceService.devices.at(0).queueDevice;
	
4. set an action that is called by the incoming events. In addition to the value the events also deliver the productID, the vendorID and the locID of the device and the cookie of the element.
		
(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
		[productID, vendorID, locID, cookie, val].postln;
});
)

(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
		[cookie, val].postln;
});
)

(
HIDDeviceService.action_({arg productID, vendorID, locID, cookie, val;
		var myval;
		[cookie, val].postln;
		myval = val;
		// { SinOsc.ar(([val]+400), 0, 0.5) }.play;
		// { SinOsc.ar(([val]+400), 0, XLine.kr(1.0, 0.001, 0.1, doneAction:12)) }.play; 
		{EnvGen.kr(Env.perc(0.1, 0.1, 1, -4), doneAction:2) * SinOsc.ar(myval*4.0, 0, 0.5)}.play;

});
)

{ SinOsc.ar(800, 0, XLine.kr(1.0, 0.001, 1, doneAction:3)) }.play; 

// start the eventloop:
HIDDeviceService.runEventLoop;
		
// stop the eventloop:
HIDDeviceService.stopEventLoop;

// poll the device
(
HIDDeviceService.buildDeviceList;
d = HIDDeviceService.devices.at(0);
e = d.elements;
e[1].name.postln;
t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		val = d.elements(i);
		// e[4].postln;
		if(val != lastval, {val = val.postln});
		});
	});
t.play;
)

// poll the device
(
HIDDeviceService.buildDeviceList;
d = HIDDeviceService.devices.at(0);
e = d.elements;

t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		// val = d.elements(i);
		e[1].postln;
		// if(val != lastval, {val = val.postln});
		})
	});
t.play;
)

// poll the device
(
HIDDeviceService.buildDeviceList;
d = HIDDeviceService.devices.at(0);

t = Task({
	var val, lastval;
	val = 0;
	loop({
		lastval = val;
		0.001.wait;
		val = d.getValue(i);
		if(val != lastval, {val = val.postln});
		})
	});
t.play;

)

HIDDeviceService.browse;