I am making a PD-based project that needs a lot of input buttons and was about to make a circuit to send varying voltage to the analogue input pins depending on which button I press.
Then a friend showed me his Raspberry Pi project where he hacked a USB computer keyboard and just replaced the buttons with his own, connecting to the R-Pi by USB.
Is there a speed/latency cost for me if I try this route instead of using the analogue ins?
It would save me a lot of soldering and also save me working out how the analogue ins work!
USB keyboard vs Analogue in/outs key matrix
Nice idea. I think the speed of that solution would be fine. Reading from USB would need to go through the Linux kernel so it wouldn't necessarily have the same hard-real-time performance as the digital or analog I/O, but in practice the delay ought to be very small, maybe a couple milliseconds at most.
The way to handle it will be to set up an AuxiliaryTask (i.e. a second thread) which handles reading from the keyboard. When you receive a character, use it to set a global variable which communicates back to the audio thread. You will have some jitter in this arrangement (i.e. timing will be quantised to the audio block size) but in practice I don't think the difference will be at all audible, especially if your block size is one of the default small sizes like 16 samples.
The filter-IIR example in the "terminal-only" is a starting place for working with the keyboard. Look at the function read_input()
.
Thanks. I guess I will try it and see if the delay is OK or not.
These buttons will be used to play musical sounds directly so timing is critical.
- Edited
If I plug a USB keyboard into the BBB, should it work with Pure Data patches straight away? Not having any luck yet....
As far as I know, libpd doesn't natively support keyboard input, especially when it is not being run from a terminal. Actually on reflection this is an interesting problem in general: normally even in C++, a Bela program will get its input from the terminal it is attached to, which is typically the console on the IDE or an SSH terminal session.
How to read from the physical keyboard, no matter where the program is running from, is a different question. I'm sure it's possible but you may want to look around for other examples of doing this on BBB or Raspberry Pi.
The [key] family of objects is not supported through libpd because it normally is handled by the GUI, which is disabled in this case...
OK so it's not gonna be easy!
PureData patches run but getting any sort of input or output to them means learning some more languages!
Is there a list of other PD commands that are not supported?
I have a couple of non-vanilla objects that I need to find work-around fors as well....
- Edited
As far as I know the only unsupported objects are [sigmund~] [bonk~] [netreceive] [netsend] [key] [keyup] [keydown] [keyname]
, but I have not tested everything else yet. I am working on a replacement for [netreceive] [netsend]
.
Also, I should look into how to dynamically load externals for libpd so that you can compile your own (or someone else's) external for Bela.
may be relevant, I pin it here: http://stackoverflow.com/questions/20943322/accessing-keys-from-linux-input-device
Thanks for the info.
If I compile with Heavy is it still the case that I can't use [key] etc?
yes, even more so. Heavy as a limited number of objects supported, full list here
nuromantix
If you end up skipping the keyboard hack and go with buttons connected to I/O. I would recommend using a multiplexer IC instead of reading different analog voltages. A multiplexer would allow you to expand the digital inputs greatly and is pretty easy to use.
Something like this one perhaps: http://www.nxp.com/documents/data_sheet/74HC_HCT4067.pdf
I actually have a couple lying about but I am a total beginner.... I understand what they do in theory but in practice how do you use it with Bela? How do you get your 8 or 16 values into Bela without using lots of inputs?
You have to write some code that cycles very quickly through all the inputs on the multiplexer to get all the inputs all the time ??
I think I get it but it seems complicated compared to just using a couple of analogue ins and a handful of resistors.
using muxers on the digital inputs would allow to increase the number of digital inputs at the expense of lowering their sampling rate. Using muxers generally requires loads of wires and using a bespoke pcb would be ideal. This would also cause troubles if you were to use rotary encoders, in which case you would need some shift registers.
Additionally, if you were to use some of the digital IOs to drive the muxer, you would then lose some of the available IOs.
If you need more than 16 digital inputs, an option could be to use the Bela multiplexer capelet, which has a 8x multiplexer connected to the analog inputs. This uses a custom PRU code to drive the multiplexer logic.
I'll leave this here as a starting to point to answer the original question (it's actually the first result when googling for "dev keyboard", but the research token itself is not very obvious)
http://stackoverflow.com/questions/2775461/linux-keyboard-event-capturing-dev-inputx
giuliomoro I'm curious about the net receive replacement for libpd...
Did you get it to work?
- Edited
Apologies for the delay. What stopped me so far is that I wanted to find a unified solution for libpd and heavy, which would not use [netsend]
and [netreceive]
, but instead something like:
[r bela_netreceive]
|
| [r bela_netereceive_port]
| /
|/
[print]
[r bela_netsend]
|
| [r bela_netsend_destination]
| /
|/
[print]
I plan to do this by the end of the week.
- Edited
In order to capture the keys from an usb-kbd and send yo Pd, I tried this and I think it work:
render.cpp
#include <fcntl.h>
#include <linux/input.h>
// Task for read the qwerty kbd
AuxiliaryTask gInputTask;
void read_kbd();
// global variables to receive keys from the auxiliary thread
bool newKeyEvent = false;
int keyValue = 0;
int keyType = 0;
in setup()
// start qwerty kbd capture thread
if((gInputTask = Bela_createAuxiliaryTask(&read_kbd, 50, "bela-read-input")) == 0)
return false;
in render()
if (newKeyEvent)
{
if(keyType == 0)
libpd_float("keyup", (int)keyValue);
if(keyType == 1)
libpd_float("key", (int)keyValue);
newKeyEvent = false;
}
Bela_scheduleAuxiliaryTask(gInputTask);
and
void read_kbd(){
// Variables keyboard control
struct input_event ev;
ssize_t n;
const char *dev = "/dev/input/event0";
int fd;
// qwerty keyboard capture
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s:.\n", dev);
return;
}
bool shouldStop = false;
int n;
while (!shouldStop && !gShouldStop)
{
n = read(fd, &ev, sizeof(ev));
if (n == (ssize_t)-1) {
shouldStop = true;
} else if (n != sizeof(ev)) {
shouldStop = true;
} else
{
if (ev.type == EV_KEY && ev.value == 0 && ev.value <= 2)
{
keyType = 0; // key released
keyValue = (int)ev.code;
newKeyEvent = true;
}
if (ev.type == EV_KEY && ev.value == 1 && ev.value <= 2)
{
keyType = 1; // key pressed
keyValue = (int)ev.code;
newKeyEvent = true;
}
// I'm filtering key repetitions
}
}
}
alexBarrachina Thanks for sharing your solution.
NOTE: I reformatted your post, you should use triple backtick (```) to enclose lines of code.