Hi,

I was wondering if there would be any chance of the KeyState Ugen being implemented for Bela? I realise it's part of the 'macugens' so maybe not considered relevant here, but it works somewhat in Linux and I find it very useful for adding simple external pedal devices. It would make porting a project I'm working on to Bela a lot simpler!

Thanks,

Mark

on my system it's in SCClassLibrary/Common/Audio/MacUGens.sc

it's there on the board (in /usr/share/SuperCollider/SCClassLibrary/Common/Audio/MacUGens.sc). Did you try using it?

Yes, when I tried it I got 'exception in GraphDef_Recv: UGen 'KeyState' not installed.'

I had a look at The Source and it looks like this is part of the UIUGens. These seem to require X11, which is disabled on the Bela build because it runs headless.

What are you trying to achieve with it?

I'm trying to use an external pedal to trigger various sub-patches in SC. I have a simple USB pedal that can be mapped to keystrokes - when I run SC in headless mode from terminal in my laptop it works fine.

In context my patches react to a live input (I'm a saxophonist), but for brevity a generic example:



s.waitForBoot({
 
	Ndef(\listener, 
		{
			var foot = KeyState.kr(38, lag:0.01);	
			SendReply.kr(Impulse.kr(2), cmdName:'/foot', values:foot);
		});

	Ndef(\sine, 
		{
			SinOsc.ar(220, mul:0.2);	
		});
		
	Ndef(\noise, 
		{
			PinkNoise.ar(0.1);	
		});

	~count = 0;
	
	OSCdef(\footReceiver, 
		{
			|msg|
		
			case
		
			{msg[3] == 1.0} {~count=~count+1}
		
			{~count==1} {~count=2; Ndef(\sine).play;}
		
			{~count==3} {~count=4; Ndef(\sine).stop; Ndef(\noise).play;}
			
			{~count==5} {Ndef(\noise).stop;}
		
		}, '/foot');
	
});

There are a few ways this could be done.
one is to connect a foot switch to one of the Bela digital inputs and then use the DigitalIn ugen. How much programmable is the pedal? If it could be made to send out MIDI instead of key presses, that could be another option. Last, leaving the pedal as it is, one could create a small keypress-to-OSC bridge, a stand-alone program that reads keyboard inputs and passes them over to OSC similarly to what the KeyCode ugen does.

Thanks 🙂 the pedal only maps to keystrokes - I considered the last option, but would running a small second program alongside SC on Bela be fine? I assumed it would only happily run one program at a time.

Also, assuming it would run fine, would it be possible to do this with Python on the Bela rather than C++?

It would be OK to have the two programs running at the same time and sure it could be python. But let's make a step back. I think the Sc HID class would do something similar, could you try it out? It's not currently enabled on Bela, but I am just rebuilt Supercollider for Bela with HID enabled now. So if it works for your on your computer then I can give you this new build.

Oh wow, thanks so much - I just tried the HID class though and it doesn't see my pedal :/ perhaps I need to go pedal shopping.
In the meantime would installing a python library on Bela be straightforward? I'm used to using python-osc, but it's a pure python library

can you create a new C++ project on Bela and replace the content of its render.cpp file with the following:

#include <fcntl.h>
#include <linux/input.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(){
	
	// Variables keyboard control
	struct input_event ev;
	const char *dev = "/dev/input/event1";

	// qwerty keyboard capture
	int fd = open(dev, O_RDONLY);
	if (fd == -1) {
		fprintf(stderr, "Cannot open %s:.\n", dev);
		return -1;
	}
	while (1)
	{
		ssize_t n = read(fd, &ev, sizeof ev);
		if (n < 0) {
			fprintf(stderr, "Error while reading: %d %s\n", errno, strerror(errno));
			return -1;
		} else if (n != sizeof(ev)) {
			fprintf(stderr, "Read unexpected length\n");
			return -1;
		} else {
			if (ev.type == EV_KEY && ev.value == 0 && ev.value <= 2)
			{
				// key released
				int keyValue = ev.code;
				printf("Released %d\n", keyValue);
			}
			if (ev.type == EV_KEY && ev.value == 1 && ev.value <= 2)
			{
				// key pressed
				int keyValue = ev.code;
				printf("Pressed %d\n", keyValue);
			}
		}
		usleep(10000);
	}
	close(fd); // won't actually get here unless an error occurs
	return 0;
}

You may have to edit the path in const char *dev = "/dev/input/event1"; if your pedal shows up at a different place ... running find /dev/input -exec ls -l {} \; may help you disambiguate.
The code is adapted from here.

If the above prints some values as you press the key then you can either use Python to read from the device and send OSC, or I can add OSC support to this. To install Python packages via automated methods you probably need to connect your board to the internet (see https://learn.bela.io/using-bela/bela-techniques/connecting-to-wifi/)).

awesome, thankyou so much!
The code runs with const char *dev = "/dev/input/event0"; , but it doesn't print any values, either from the pedal or keyboard. When I ran find /dev/input -exec ls -l {} \; I got:

total 0
drwxr-xr-x 2 root root      60 Nov  3  2016 by-path
crw-rw---- 1 root input 13, 64 Nov  3  2016 event0
crw-rw---- 1 root input 13, 63 Nov  3  2016 mice
total 0
lrwxrwxrwx 1 root root 9 Nov  3  2016 platform-44e0b000.i2c-event -> ../event0
lrwxrwxrwx 1 root root 9 Nov  3  2016 /dev/input/by-path/platform-44e0b000.i2c-event -> ../event0
crw-rw---- 1 root input 13, 64 Nov  3  2016 /dev/input/event0
crw-rw---- 1 root input 13, 63 Nov  3  2016 /dev/input/mice

event0 is the built-in power-management IC, so that's not your pedal/keyboard. I am wondering if it's being recognised appropriately ... what do you get from lsusb? And what if you run dmesg | tail -n 20 a few seconds after you plug in your device?

I'd love to get this working in C++ - if I bought a dongle then I could get this done in Python via the pynput and python-osc libs, but I'm a bit worried about the CPU overhead.

I don't think there'd be much overhead in python: the thread would be mostly doing nothing - just like now - : it is just waiting for the file descriptor to be ready (i.e.: a new HID even was received), processing it and sending it over via OSC. But if you cannot get this to work with the test program above, then python won't fix it!
What Bela image version have you got, by the way? grep v0 /etc/motd will tell you

lsusb gives me Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub.

dmesg | tail -n 20 returns:

[    6.863608] omap_rng 48310000.rng: OMAP Random Number Generator ver. 20
[    7.572355] omap-sham 53100000.sham: hw accel on OMAP rev 4.3
[    7.819000] omap-aes 53500000.aes: OMAP AES hw accel rev: 3.2
[    9.281787] random: nonblocking pool is initialized
[    9.307083] using random self ethernet address
[    9.307119] using random host ethernet address
[    9.372905] using random self ethernet address
[    9.372942] using random host ethernet address
[    9.444396] Mass Storage Function, version: 2009/09/11
[    9.444433] LUN: removable file: (no medium)
[   10.877295] usb0: HOST MAC be:1a:b7:d1:9f:f3
[   10.879785] usb0: MAC be:1a:b7:d1:9f:f4
[   10.883991] usb1: HOST MAC be:1a:b7:d1:9f:f6
[   10.884365] usb1: MAC be:1a:b7:d1:9f:f7
[   11.296113] configfs-gadget gadget: high-speed config #1: c
[   11.585867] net eth0: initializing cpsw version 1.12 (0)
[   11.585903] net eth0: initialized cpsw ale version 1.4
[   11.585916] net eth0: ALE Table size 1024
[   11.588516] net eth0: phy found : id is : 0x7c0f1
[   11.607095] IPv6: ADDRCONF(NETDEV_UP): eth0: link is not ready

version is Bela image, v0.3.7c, 27 February 2020

It seems like your USB pedal device is not detected at all ... just checking: is the pedal plugged directly into Bela's USB host port?