The aim of Brain-Computer Interface (BCI) is to improve the autonomy of people with severe motor disabilities by new communication and control options. It is commonly known that either if you perform a movement, or you think about actually doing this movement, the same area in the brain is activated. Therefore, the point with these kind of people that cannot move but can think about moving their limbs is to use motor-related signals produced by them and create a new communication channel. We understand Lateralized Readiness Potential (LRP) and Event-Related Desyncronization (ERD) as motor-related signals, among others.
In controls, imagined movements produce motor related signals, but less pronunced in comparision to executed movements. One of the reasons is the duality of the task of imaging a movement but at the same time vetoing the actual movement. Therefore a real movement made by a healthy subject is more like the motor-command in disabled persons that an imagined movements.
My main interest in the following experiment was the examination of stability and refractory behaviour of motor related brain signals with increasing speed of execution and the associated bit-rate. For this reason, I examined the cortical signals of executed finger tapping movements in experimental settings with different movement speeds. I started a series of experiments with volunteers performing self-paced finger-movements on a two external trigger (buttons) hardwired into the OpenBCI 32bit board.
Currently OpenBCI GUI edited for the finger tapping experiment
The main idea of this OpenBCI GUI Left-hand vs. Right-hand finger tapping experiment version is to
// Create variables
Button bpm30;
Button bpm45;
Button bpm60;
Button bpm120;
boolean RandomButtonPressed = false;
boolean bpm30ButtonPressed = false;
boolean bpm45ButtonPressed = false;
boolean bpm60ButtonPressed = false;
boolean bpm120ButtonPressed = false;
// Audio Files
Minim minim;
AudioPlayer player30bpm;
AudioPlayer player45bpm;
AudioPlayer player60bpm;
AudioPlayer player120bpm;
// void setup
bpm30 = new Button (int(x+180), int(y+140), 60, 20, "30 bpm", 10);
bpm45 = new Button (int(x+180), int(y+165), 60, 20, "45 bpm", 10);
bpm60 = new Button (int(x+180), int(y+190), 60, 20, "60 bpm", 10);
bpm120 = new Button (int(x+180), int(y+215), 60, 20, "120 bpm", 10);
// Load Audio Files
minim = new Minim(this); // we pass this to Minim so that it can load files from the data directory
// loadFile will look in all the same places as loadImage does. This means that you can find files that are in the data folder and the sketch folder. You can also pass an absolute path, or a URL.
player30bpm = minim.loadFile("/data/30BPM.mp3");
player45bpm = minim.loadFile("/data/45BPM.mp3");
player60bpm = minim.loadFile("/data/60BPM.mp3");
player120bpm = minim.loadFile("/data/120BPM.mp3");

Once you have preselected either 30 bpm, 45 bpm, 60 bpm or 120 bpm, when you press “Start Experiment” a Dropbox link pops-up.

The code used is so easy to implement, since the iterations and conditions subjected to whatever BPM options is selected are pretty strightfoward and legit:
if (TestRunning) {
if (bpm30ButtonPressed) {
link("https://www.dropbox.com/s/2f3l4vph5mnbkmc/30BPM.mp3.mp3?dl=0");
bpm30ButtonPressed = false;
}
if (bpm45ButtonPressed) {
link("https://www.dropbox.com/s/kjwrd6017r9dc31/45BPM.mp3?dl=0");
bpm45ButtonPressed = false;
}
if (bpm60ButtonPressed) {
link("https://www.dropbox.com/s/egc04c5no4541e5/60BPM.mp3?dl=0");
bpm60ButtonPressed = false;
}
if (bpm120ButtonPressed) {
link("https://www.dropbox.com/s/sjqsptglnayx675/120BPM.mp3?dl=0");
bpm120ButtonPressed = false;
}
}
Improvements
First of all, I would like to say that this is the first draft of this OpenBCI GUI version. So, a lot of improvement needs to be done and implemented. I made a to-do list with all the potential improvements that I could apply to my first draft in order to become my “perfect” version for my proposes.
- Play the audio files in Processing. I would love to be able to play the audio files in Processing. Although I tried to play them with the Minim function, it seems that I’m not able to upload the audio files. Therefore, I cannot play neither of them when the script is running and I’ve selected one of the bpm options. Here is the error that appears in the OpenBCI GUI console:
==== JavaSound Minim Error ==== ==== Couldn't find a sketchPath method on the file loading object provided! ==== File recording will be disabled. ==== JavaSound Minim Error ==== ==== Couldn't find a createInput method in the file loading object provided! ==== File loading will be disabled. ==== JavaSound Minim Error ==== ==== java.lang.NullPointerException === Minim Error === === Couldn't load the file /data/30BPM.mp3 ==== JavaSound Minim Error ==== ==== java.lang.NullPointerException === Minim Error === === Couldn't load the file /data/45BPM.mp3 ==== JavaSound Minim Error ==== ==== java.lang.NullPointerException === Minim Error === === Couldn't load the file /data/60BPM.mp3 ==== JavaSound Minim Error ==== ==== java.lang.NullPointerException === Minim Error === === Couldn't load the file /data/120BPM.mp3
- Draw the waveforms. To apport a creative way to play the songs, I thought that it would be fancy to draw the waveforms accordingly to the bpm rate. Its based on the example give by Processing located in File > Examples… > Contributed Libraries > Minim > Basics > PlayAFile. Thus, I created an independent script with Processing and I tried to implement it in my Playground tab with my experiment code, but since I am not able to load and execute the audio files, I cannot run it. What a shame, right?
import ddf.minim.*;
Minim minim;
AudioPlayer player;
void setup() {
size(512, 200, P3D);
// we pass this to Minim so that it can load files from the data directory
minim = new Minim(this);
// loadFile will look in all the same places as loadImage does.
// this means you can find files that are in the data folder and the
// sketch folder. you can also pass an absolute path, or a URL.
player = minim.loadFile("30BPM.mp3");
}
void draw() {
background(0);
stroke(255);
// draw the waveforms
// the values returned by left.get() and right.get() will be between -1 and 1,
// so we need to scale them up to see the waveform
// note that if the file is MONO, left.get() and right.get() will return the same value
for(int i = 0; i < player.bufferSize() - 1; i++) {
float x1 = map( i, 0, player.bufferSize(), 0, width );
float x2 = map( i+1, 0, player.bufferSize(), 0, width );
line( x1, 50 + player.left.get(i)*50, x2, 50 + player.left.get(i+1)*50 );
//line( x1, 150 + player.right.get(i)*50, x2, 150 + player.right.get(i+1)*50 );
}
// draw a line to show where in the song playback is currently located
float posx = map(player.position(), 0, player.length(), 0, width);
stroke(60,80,140);
line(posx, 0, posx, height);
if ( player.isPlaying()) {
text("Press any key to pause playback.", 10, 20 );
} else {
text("Press any key to start playback.", 10, 20 );
}
}
void keyPressed()
{
if ( player.isPlaying()) {
player.pause();
}
// if the player is at the end of the file,
// we have to rewind it before telling it to play again
else if ( player.position() == player.length()) {
player.rewind();
player.play();
} else {
player.play();
}
}

- Use Radio Buttons. To implement this kind of buttons, you need to download the “Radio” class from Processing. Likewise, I created an independent script with Radio buttons to select the hand that the user wants to use to perform the experiment, and the bpm of the audio files.
class Radio {
int x, y;
int size, dotSize;
color baseGray, dotGray;
boolean checked = false;
int me;
Radio[] others;
Radio (int xp, int yp, int s, color b, color d, int m, Radio[] o) {
x = xp;
y = yp;
size = s;
dotSize = size - size/3;;
baseGray = b;
dotGray = d;
others = o;
me = m;
}
// Updates the boolean value press, returns true or false
boolean press (float mx, float my) {
if (dist(x, y, mx, my) < size/2) {
checked = true;
for (int i=0; i < others.length; i++) {
if (i!=me) {
others[i].checked = false;
}}
return true;
} else {
return false;
}}
// Draws the element to the display window
void display() {
noStroke();
fill(baseGray);
ellipse(x, y, size, size);
if (checked == true) {
fill (dotGray);
ellipse(x, y, dotSize, dotSize);
}}
}

However, when I try to import the code to the OpenBCI GUI I simply cannot do it. The buttons are drawn in the main page, not in the Playground tab.
References
- Processing website: https://processing.org/
- Processing examples.
Leave a Reply
You must be logged in to post a comment.