Monday, 14 October 2013

USB controllers in PD

Todays blog post is about a deceptively simple subject which can instantly expand your capabilities in Pure Data, Human Interface Devices or HID.

This was one of the things to excite me about Pd usage in the early days because it introduces what could be termed the 'alchemy' of  computer programming. Simply termed, we can turn a kind of thing with a specific purpose, such as a joypad, into the same thing, with a very different purpose, a musical instrument.

So today I'm working with this rather simple setup:



Now, that's a nice, cheap, third-party USB joypad, I bought for £15, but if you fish around online you can find cheaper, still. Now, almost all game controllers for computers use a set of standards known as HID (Human Interface Device). Which strangely enough is also the name of the object which we can use to get this information into Pd.

Try this patch (remember to plug in a USB controller before opening Pd):

Step 1: Finding your HID device



This is a simple patch to start with, because hid is quite complicated there's a few different messages you can feed into the top. The message 'print' when you haven't told it which device to listen to yet will print out a list of available hid devices in your Pd terminal, looking something like this...


Now, we can see a list of devices, and that hte USB joystick (curiously named MY-POWER when the name ORB is printed on the pad itself) is Device 12. You may also see keyboards, mice, graphics pads etc on this list.

Note that next time you plug in your joypad (or other kind of controller) it may not have the same device number, so you might have to go through this process again when you open a saved patch.

The next step is to open this device and see what information Pd can read from it...

Step 2: Look at the device, having found it



Now, clicking on 'open 12' will tell hid to read the device we found in the previous step, and then the purpose of 'print' has changed. Instead of listing devices Pd can see, it will tell you what parameters it can read from that device. So clicking 'print' will result in a readout like this one...


Now, you can see that we have messages which Pd can get from the controller, 12 btn messages (which will send 1 when a button is pushed, and 0 when it is released) and 7 absolute axes, which are sliding-scale type messages. If, having opened a hid device, we feed hid a 1 (usually from a toggle, but you could feed it in from a message, too) it will start polling (basically, listening to) these events from the controller.

Let's try setting this to poll, then feeding the results out to the terminal via an object called print (not to be confused with print from the message, mentioned above.

Step 3: have a look at what's available 



All we've done here is pipe the output of hid into print, which puts everything it sees onto the terminal, so when I push some buttons on my controller we see something a little bit like this...


Now, this is just a list of messages, but we can see that there's a certain structure there. Firstly there's three things separated by a space, which Pd reads as a list. Firstly the contents of the TYPE column we saw above, then the name of that parameter, then a value of 0 or 1.

There's also a miscellaneous scan parameter, which seems to identify the button being used. I don't really know what this is for, but I know we can safely ignore it.

You'll also notice that every message (1 for on, 0 for off) is sent twice. This is a problem known as 'debouncing' which some controllers are prone to. There are ways around this, but for everything we're going to do here, it won't matter.

The next thing we need to know in order to make this information useful is how to just get the last part of the list, for just one button. For this we're going to use route. All route does is list (without that first item), and everything else out of it's right-hand outlet.

If route has more than one argument, it will gain additional outlets, if the first item in an incoming list matches the first argument, it'll be output via the first outlet. The second argument, the second outlet, and so on...

Step 4: Use route to focus on the controls you're interested in.



So all I've done here is route the lists starting with 'key' to the second route, where it takes the messages btn_0, btn_1, btn_2 and btn_3 and outputs them to four toggles. When I took this screenshot I was holding one of those buttons, so you can see that one toggle is selected.

And that's basically all you need to know about getting (or Mapping) inputs from a hid device into Pd. But we don't want to stop there, what about those joysticks? and the d-pad? Well, with the same process we can route their inputs into our patch, too.

Step 5: A few more mappings...



So there you have it, both of the joysticks output two axes, and moving them around I can easily learn that they range from 0 (at the top, or far left of it's range of motion) to 255 (at the bottom, or far right) and the resting position has both at 128.

The d-pad (direction control on the left hand side of the pad) also outputs two axes of motion, although these are only ever -1 (up and left), 0 (resting) or 1 (down and right).

In the snapshot above I was holding one stick to the bottom-right and also the d-pad.

I think it's time for a little alchemy, let's hide the patch so far in a sub-patch (see Putting Pure Data in a Box) and use some of these controls to make music.

Step 6: Mapping controllers to a simple synth




Now there's a few things here from previous patches, firstly the object 'pd controller' contains the hid patch we've been working on, only I've added a few sends to it (named b1 for button 1 etc. lx for the left stick's x axis etc.). As you can see here:


The patch outside it contains a few things from previous tutorials, an array with 15 numbers (representing two octaves of the major scale), a maxlib/scale which converts the 0 to 255 we have to the 0 to 15 we want. This goes through i to make sure it's an integer (whole number) and to tabread, which reads a number from the array, scale. we add 50 then smooth out the edges with a line~. This is converted to a frequency with mtof~ and feeds an oscillator.

I've then brought in one of my buttons (b1) to turn the volume on or off for the oscillator, multiplied it down a little and fed it to the sound card with dac~

Once again I've described each part of a Pd chain to tell you it's function, but if you haven't read all my other blog posts, this basically turns the left-right motion of the left joystick into a pitch control, in a given scale, and one of our buttons into an on-off switch. This is a simple musical instrument. With a little practise you can play a tune on this.

Now, just for fun, I'm going to use the up-down motion as a volume control and lengthen the envelope on the button control...


So the left stick is taking on the duties of a bit more expression. This also opens the patch up to something of a money shot. Why not have a synth on each of these 4 buttons, an octave apart? One of the strengths of Pd is to quickly duplicate and modify code, so let's try it...

Step 7: A modified joypad quartet



Now, I've done a few things here. Firstly I've moved that volume control to the top of the patch, and sent it to the bottom part of the patch with an audio send (s~ vol), then I've duplicated the bottom part of my patch 4 times. I added 12 to each successive midi note (making it an octave higher), then I used a different button send to turn each one on and off. Hey presto, I can play at a different octave by pressing each of the four buttons.

I also changed all the osc~ objects to phasor~ for a different tone, and lowered the initial + to make the lowest tone a bit lower.

Now is probably the time for a little demo, but first, I should warn of some of the pitfalls of working with cheap and cheerful gaming controllers.

Firstly, you'll find the range of motion on joypads is much narrower than you think. That is, the range which isn't the extreme top or bottom end, or dead centre only takes up a small amount of the space you can move the joystick.

Also, you'll probably trip up over the fact that the top of a stick's motion is 0, and not the bottom.


Well, that range of motion issue has made it a little limited, and it is a very simple instrument, but here it is. My custom joypad instrument and a little exploration of the sounds it's making...



No comments:

Post a Comment