-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBrainBeats.pde~
409 lines (385 loc) · 14.9 KB
/
BrainBeats.pde~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
// Ricardo Diaz: CS Student at Universidad del Valle (Colombia), Camaleón Research Group //<>//
// CreativeCommons-Sharealike
// BrainBeats:
// Uses brainwave measurements sent from a NeuroSky EEG device (MindWave) to determine
// which pattern (from an array) to loop. Sends out MIDI CC values based
// on the MindSet's Attention & Meditation values and displays brainwave measurement on screen
// Special thanks to Collin Cunningham for providing the base code for this project
// you can find more of his work here: http://www.collinmel.com/
// Working on Processing 3.3.7
// Required Libraries:
// proMIDI: https://github.com/dearmash/Processing/tree/master/libraries/promidi
// MindSetProcessing : http://jorgecardoso.eu/processing/MindSetProcessing/
// Required Devices:
// NeuroSky MindWave: https://store.neurosky.com/
// Pc with BlueTooth connectivity: Currently working on Lenovo G40-30, Win 8.1
/** Processing custom library */
import processing.serial.*;
/** proMIDI library */
import promidi.*;
/** MindSetProcessing library */
import pt.citar.diablu.processing.mindset.*;
/** MindWave variables change serialPort for the serial port using the EEG device, something like COM5 on Windows or /dev/ttys0 on linux */
/** Use always the output com port -> MindWave Mobile 'Dev A' */
MindSet mindset;
String serialPort = "COM5";
/** Use these to scale frequency levels to something more usable */
float thetaFactor = 1000.0;
float alphaFactor = 1000.0;
float deltaFactor = 1000.0;
float betaFactor = 500.0;
float gammaFactor = 500.0;
int thetaVal, alphaVal, betaVal, gammaVal, attVal, medVal, deltaVal, highAlphaVal, midGammaVal, attOut, medOut = 0;
//MIDI VARIABLES
int tempo = 145;
//these 2 variables define the controller #s which we'll send out over MIDI
int attCC = 8;
int medCC = 9;
//These are that MIDI notes that I have setup with each instrument in my DAW
int G4 = 67;
int B4 = 71;
int D5 = 74;
int G5Flat = 78;
int G2 = 43;
int D3 = 50;
int G3 = 55;
//curious, should control note's duration, no luck with it myself, ymmv
int noteLength = 1;
//raw values
int raw_delta, raw_theta, raw_alpha, raw_beta, raw_gamma, raw_high_alpha, raw_mid_gamma = 0;
//more MIDI parts
Sequencer sequencer;
Song song;
Track g4Track, b4Track, d5Track, g5FlatTrack, g2Track, d3Track, g3Track;
Controller attController, medController;
MidiOut midiOut;
void setup() {
//MIDI Setup
//initializes all the components of our proMIDI sequencer
sequencer = new Sequencer();
//Use this method to get instance of MidiIO. It makes sure that only one instance of MidiIO is initialized. You have to give this method a reference to
//your applet, to let promidi communicate with it.
MidiIO midiIO = MidiIO.getInstance();
//Muestra los dispositivos MIDI disponibles en el equipo
midiIO.printDevices();
midiIO.closeOutput(1);
//Abre un Midiout usando el primer dispositivo y el primer canal
midiOut = midiIO.getMidiOut(0, 1);
//Se definen los parametros iniciales de atencion y meditacion
//Controller Class -> representa un controlador MIDI
//Tiene un numero y un valor se pueden recibir valores de midi ins y enviarlos a midi outs
attController = new Controller(attCC, 100);
medController = new Controller(medCC, 100);
// A song is a data structure containing musical information
//that can be played back by the proMIDI sequencer object. Specifically, the
//song contains timing information and one or more tracks. Each track consists of a
//series of MIDI events (such as note-ons, note-offs, program changes, and meta-events).
song = new Song("beat", tempo);
//A track handles all midiEvents of a song for a certain midiout. You can directly
//add Events like Notes or ControllerChanges to it or also work with patterns.
g4Track = new Track("g4", midiOut);
//Establece el tiempo de duracion de duracion de una nota: 8-> corcheas
g4Track.setQuantization(Q._1_8);
b4Track = new Track("b4", midiOut);
b4Track.setQuantization(Q._1_8);
d5Track = new Track("d5", midiOut);
d5Track.setQuantization(Q._1_8);
g5FlatTrack = new Track("g5Flat", midiOut);
g5FlatTrack.setQuantization(Q._1_8);
g2Track = new Track("g2", midiOut);
g2Track.setQuantization(Q._1_8);
d3Track = new Track("d3", midiOut);
d3Track.setQuantization(Q._1_8);
g3Track = new Track("g3", midiOut);
g3Track.setQuantization(Q._1_8);
song.addTrack(g4Track);
song.addTrack(b4Track);
song.addTrack(d5Track);
song.addTrack(g5FlatTrack);
song.addTrack(g2Track);
song.addTrack(d3Track);
song.addTrack(g3Track);
sequencer.setSong(song);
//Sets the startpoint of the loop the sequencer should play
sequencer.setLoopStartPoint(0);
//Sets the endpoint of the loop the sequencer should play
sequencer.setLoopEndPoint(512);
//Sets how often the loop of the sequencer has to be played.
sequencer.setLoopCount(-1);
//MINDSET SETUP
//display the list of avaible serial ports for your convenience
println(Serial.list());
println("");
//start a connection to the mindset
mindset = new MindSet(this, serialPort);
}
//simple instructions text
void draw() {
String s = "Left click to start sequencer, right click to stop.";
text(s, 15, 20, 70, 70);
}
//mouse control for starting/stopping the sequencer
void mousePressed() {
if (mouseButton == LEFT) {
sequencer.start();
println("sequencer is running");
} else if (mouseButton == RIGHT) {
sequencer.stop();
println("sequencer has stopped");
}
}
//We don't use these in the program, but they triggered an error when undefined sooo ...
public void poorSignalEvent(int sig) {
}
public void blinkEvent(int binkStrength) {
}
public void rawEvent(int rawEvents[]) {
}
//Here we get the MindSet's estimation of the user's attention level
public void attentionEvent(int attentionLevel) {
//println("Attention: " + attentionLevel);
//and convert it to a value between 0-127 for MIDI
attVal = round(attentionLevel * 1.27);
}
//And here we get the MindSet's estimation of the user's meditation level
public void meditationEvent(int meditationLevel) {
//println("Meditation: " + meditationLevel);
//and convert it to a value between 0-127 for MIDI
medVal = round(meditationLevel * 1.27);
}
//Here we get individual frequency levels from the MindSet
public void eegEvent(int delta, int theta, int low_alpha, int high_alpha, int low_beta, int high_beta, int low_gamma, int mid_gamma) {
raw_delta = delta;
raw_theta = theta;
raw_alpha = (low_alpha + high_alpha)/2;
raw_beta = (low_beta + high_beta)/2;
raw_gamma = (low_gamma + mid_gamma)/2;
raw_high_alpha = high_alpha;
raw_mid_gamma = mid_gamma;
deltaVal = convertVal(delta, thetaFactor);
highAlphaVal = convertVal(high_alpha, alphaFactor);
midGammaVal = convertVal(mid_gamma, gammaFactor);
thetaVal = convertVal(theta, thetaFactor);
alphaVal = convertVal((low_alpha + high_alpha)/2, alphaFactor);
betaVal = convertVal((low_beta + high_beta)/2, betaFactor);
gammaVal = convertVal((low_gamma + mid_gamma)/2, gammaFactor);
resetPatterns();
}
//This function keeps a value from going negative and then scales it down using 'factor' value
int convertVal(float val, float factor) {
if (val < 0.0) {
val = 0.0;
}
int outVal = round(val/factor);
return outVal;
}
public void creatingMusic(String note)
{
int cuantization = 0;
int noteValue = 0;
int pattMax = notePatt.length - 1;
//send attention & meditation values as MIDI CC messages
//Se usan los niveles de atención y relajación para cambiar el sonido general del beat
medController = new Controller(medCC, medVal);
midiOut.sendController(medController);
attController = new Controller(attCC, attVal);
midiOut.sendController(attController);
//this could be much more elegant (& shorter), but it works //Se aisgna cada onda a un instrumento de percusion
//thetaVal -> G4
//alphaVal -> B4
//betaVal -> D5
//gammaVal -> G5Flat
//Cada nivel de frecuencia determina que patron de la lista se reproduce
if (note.equals("g4"))
{
song.removeTrack(g4Track);
g4Track = new Track(note, midiOut);
g4Track.setQuantization(Q._1_8);
cuantization = constrain(thetaVal, 0, pattMax);
noteValue = G4;
println("C value (Theta): " + cuantization + "|" + "Theta: " + thetaVal + "|" + raw_theta );
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
g4Track.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(g4Track);
} else if (note.equals("b4"))
{
song.removeTrack(b4Track);
b4Track = new Track("b4", midiOut);
b4Track.setQuantization(Q._1_8);
cuantization = constrain(alphaVal, 0, pattMax);
noteValue = B4;
println("C value (Alpha): " + cuantization + "|" + "Alpha " + alphaVal + "|" + raw_alpha);
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
b4Track.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(b4Track);
} else if (note.equals("d5"))
{
song.removeTrack(d5Track);
d5Track = new Track("d5", midiOut);
d5Track.setQuantization(Q._1_8);
cuantization = constrain(betaVal, 0, pattMax);
noteValue = D5;
println("C value (Beta): " + cuantization + "|" + "Beta " + betaVal + "|" + raw_beta);
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
d5Track.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(d5Track);
} else if (note.equals("g5Flat"))
{
song.removeTrack(g5FlatTrack);
g5FlatTrack = new Track("g5Flat", midiOut);
g5FlatTrack.setQuantization(Q._1_8);
cuantization = constrain(gammaVal, 0, pattMax);
noteValue = G5Flat;
println("C value (G5Flat): " + cuantization + "|" + "Gamma " + gammaVal + "|" + raw_gamma);
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
g5FlatTrack.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(g5FlatTrack);
} else if (note.equals("g2"))
{
song.removeTrack(g2Track);
g2Track = new Track ("g2", midiOut);
g2Track.setQuantization(Q._1_8);
cuantization = constrain(deltaVal, 0, pattMax);
noteValue = G2;
println("C value (Delta): " + cuantization + "|" + "Delta " + deltaVal + "|" + raw_delta);
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
g2Track.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(g2Track);
} else if (note.equals("d3"))
{
song.removeTrack(d3Track);
d3Track = new Track ("d3", midiOut);
d3Track.setQuantization(Q._1_8);
cuantization = constrain(highAlphaVal, 0, pattMax);
noteValue = D3;
println("C value (HighAplha): " + cuantization + "|" + "HighAplha " + highAlphaVal + "|" + raw_high_alpha);
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
d3Track.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(d3Track);
} else if (note.equals("g3"))
{
song.removeTrack(g3Track);
g3Track = new Track ("g3", midiOut);
g3Track.setQuantization(Q._1_8);
cuantization = constrain(midGammaVal, 0, pattMax);
noteValue = G3;
println("C value (MidGamma): " + cuantization + "|" + "MidGamma " + midGammaVal + "|" + raw_mid_gamma);
for (int i=(notePatt[cuantization].length-1); i>=0; i--) {
//The tick is the position of an event in a sequence, is the unit of time
int tick = notePatt[cuantization][i];
//Añade un nuevo evento. Note: nota, velocidad, duracion
g3Track.addEvent(new Note(noteValue, 100, noteLength), tick);
}
song.addTrack(g3Track);
}
}
// This function uses the values we received from the MindSet to select a note pattern from our array
// ... and then it adds that pattern to the proMIDI library's built in sequencer (which is really cool!)
void resetPatterns() {
creatingMusic("g4");
creatingMusic("b4");
creatingMusic("d5");
creatingMusic("g5Flat");
creatingMusic("g2");
creatingMusic("d3");
creatingMusic("g3");
}
//hey look - an array of pattern arrays (a multidimensional array) - COOL!
//These are the note locations/patterns we choose from for each percussion instrument
//(we put this @ the bottom just because it's really long & gets in the way)
//Patrones que funcionan como secuenciaas de notas.
//Cada numero determina la ocurrencia una nota dentro de una escala
int notePatt[][] = {
{2},
{3},
{4},
{5},
{6},
{7},
{0, 2},
{1, 6},
{2, 6},
{3, 7},
{4, 7},
{4, 5},
{1, 2},
{3, 4},
{1, 5},
{0, 4, 7},
{1, 4, 7},
{1, 5, 6},
{2, 3, 7},
{2, 4, 6},
{2, 5, 7},
{3, 2, 6},
{3, 4, 7},
{0, 2, 4, 6},
{0, 2, 5, 6},
{0, 1, 2, 6},
{1, 2, 5, 6},
{1, 4, 5, 6},
{1, 4, 5, 7},
{2, 4, 5, 7},
{2, 3, 5, 7},
{2, 3, 6, 7},
{3, 4, 5, 7},
{0, 2, 4, 5, 6},
{0, 1, 2, 4, 6},
{0, 2, 3, 4, 6},
{1, 3, 4, 5, 6},
{1, 3, 4, 5, 7},
{2, 3, 4, 5, 6},
{2, 3, 4, 5, 7},
{3, 4, 5, 6, 7},
{1, 2, 3, 4, 5, 6},
{1, 2, 3, 4, 5, 7},
{0, 2, 3, 4, 5, 7},
{0, 1, 2, 3, 4, 5},
{2, 3, 4, 5, 6, 7},
{0, 3, 4, 5, 6, 7},
{0, 1, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 7},
{0, 1, 2, 3, 4, 6, 7},
{0, 1, 2, 3, 5, 6, 7},
{0, 1, 2, 4, 5, 6, 7},
{0, 1, 3, 4, 5, 6, 7},
{0, 2, 3, 4, 5, 6, 7},
{1, 2, 3, 4, 5, 6, 7},
{1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7}, //these were duplicated to fill out the list & drumfills in playback
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 1, 2, 3, 4, 5, 6, 7},
};