We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hi there,
a bit of background.
I am currently trying to send data from an EEG that i have built being processed by processing. The example shown in the link shows how to send data with a mouseclick, is there any way to constantly send data from a particular part of the code? For me i would need to send the data from the frequency of the wave and the amplitude.
http://learning.codasign.com/index.php?title=Sending_and_Receiving_OSC_Data_Using_Processing
also when i go to place this code in the sketch that processes the EEG, there seem to be errors such as "EOF expected found..."
So what im asking is:
Where should i put the osc send within the rest of the code?
Any ideas on what i would have to send in order to get the frequency and amplitude of waveforms?
How do i send a constant stream of data?
CODE FOLLOWS:
/* Reading and Visualizing EEG Data * by Christian Henry. * Reads in EEG data through the microphone input of the * computer, then displays the signal in time, its frequency * components, and then averages of frequencies that estimate * the concentration of different brain waves. * * For reference, the frequency bars are ordered/classified as * follows: * * 1 - blue -------- delta * 2 - blue/purple - theta * 3 - purple ------ alpha * 4 - purple/red -- low beta * 5 - dark red ---- mid beta * 6 - red --------- high beta * * This sketch will measure all brain waves, from 0 - 30 Hz. It does * best, however, measuring alpha waves across the occipital lobe. * To view this function, play the program, click the window to * make sure its in "focus", and hit the "a" key to bandpass the alpha * waves only. The alpha wave bar is the 3rd one (purple), and should * increase in height by 2-3x when you close your eyes and relax * (you'll see it for a second or two after you open your eyes, before it * averages back down). */ /* One issue: when taking the FFT of the data, it seems as if the frequency bands have a bandwidth of 1.33 instead of 1, as 60Hz noise peaks out at band 45. This is worked around by using the scaleFreq parameter, which is used frequently. */ import ddf.minim.*; import ddf.minim.signals.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; //Important constants that may need to be changed. float timeScale = 50; //scales the amplitude of time-domain data, can be changed static float normalScale = 50; static float alphaScale = 100; static int freqAvgScale = 50; //does same for averages of frequency data static int alphaCenter = 12; static int alphaBandwidth = 2; //really bandwidth divided by 2 static int betaCenter = 24; static int betaBandwidth = 2; //Variables used to store data functions/effects. Minim minim; AudioInput in; FFT fft; NotchFilter notch; LowPassSP lpSP; LowPassFS lpFS; BandPass betaFilter; BandPass alphaFilter; //Constants mainly used for scaling the data to readable sizes. int windowLength = 840; int windowHeight = 500; int FFTheight; float scaling[] = {.00202,.002449/2,.0075502/2,.00589,.008864,.01777}; float offset[] = {0,0,0,0,0,0}; float amplify[] = {1,1,1,1,1,1}; float maximum[] = {0,0,0,0,0,0}; float scaledMaximum[] = {0,0,0,0,0,0}; int FFTrectWidth = 6; float scaleFreq = 1.33f; float timeDomainAverage = 0; //Variables used to handle bad data int cutoffHeight = 200; //frequency height to throw out "bad data" for averaging after float absoluteCutoff = 1.5; boolean absoluteBadDataFlag; //data that is bad because it's way too far out of our desired range -- // ex: shaking your head for a second boolean averageBadDataFlag; //data that's bad because it spikes too far outside of the average for //that second -- // ex: blinking your eyes for a split second //Constants used to create a running average of the data. float[][] averages; int averageLength = 200; //averages about the last 5 seconds worth of data int averageBins = 6; //we have 6 types of brain waves int counter = 0; void setup() { //initialize array of averages for running average calculation averages = new float[averageBins][averageLength]; for (int i = 0; i < averageBins; i++){ for (int j = 0; j < averageLength; j++){ averages[i][j] = 0; } } //set some drawing parameters windowLength = 840; windowHeight = 500; FFTheight = windowHeight - 200; size(windowLength, windowHeight, P2D); //initialize minim, as well as some filters minim = new Minim(this); minim.debugOn(); notch = new NotchFilter(60, 10, 32768); lpSP = new LowPassSP(40, 32768); lpFS = new LowPassFS(60, 32768); betaFilter = new BandPass(betaCenter/scaleFreq,betaBandwidth/scaleFreq,32768); alphaFilter = new BandPass(alphaCenter/scaleFreq,alphaBandwidth/scaleFreq,32768); // get a line in from Minim, default bit depth is 16 in = minim.getLineIn(Minim.MONO, 8192*4); in.addEffect(notch); //initialize FFT fft = new FFT(in.bufferSize(), in.bufferSize()); fft.window(FFT.HAMMING); rectMode(CORNERS); println(fft.getBandWidth()); } void draw() { /*badDataFlag handles any "artifacts" we may pick up while recording the data. Artifacts are essentially imperfections in the data recording -- they can come from muscle movements, blinking, anything that disturbs the electrodes. If the program encounters a set of data that spikes out of a reasonable window (controlled by the variable cutoffHeight), it won't consider that data when computing the running average. */ absoluteBadDataFlag = false; averageBadDataFlag = false; fft.forward(in.mix); //compute FFT background(0); //make sure the background color is black stroke(255); //and that time data is drawn in white line(0,100,windowLength,100); //line separating time and frequency data drawSignalData(); //check for spikes relative to other data for (int i = 0; i < windowLength - 1; i++){ if (abs(in.left.get((i+1)*round(in.bufferSize()/windowLength))) > timeDomainAverage*4) averageBadDataFlag = true; } displayText(); displayFreqAverages(); counter++; } //Calls function to zoom into average bars when you right click on the average bars. //Scales depending on position of click. void mousePressed(){ if (mouseButton == RIGHT && mouseY > FFTheight){ scaleAverage(floor(mouseX/(windowLength/averageBins)), windowHeight - mouseY); } } //Zooms into average bars to show small fluctuations better. New range (from original) is //from position clicked on to a maximum height such that the previously logged maximum fills 75% of the //current bar. void scaleAverage(int bin, float pos){ offset[bin] += pos/amplify[bin]; println(offset[bin]); amplify[bin] *= 200/(1.33f*(scaledMaximum[bin] - pos)); println(amplify[bin]); maximum[bin] = 0; scaledMaximum[bin] = 0; } //Hitting number keys will reset that bin of averages, hitting "`" will wipe them all. void keyPressed(){ if (key == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6'){ char data[] = {key}; String str1 = new String(data); int keyNum = Integer.parseInt(str1); keyNum -= 1; //shift down 1 since array is zero-indexed offset[keyNum] = 0; amplify[keyNum] *= 1; maximum[keyNum] = 0; scaledMaximum[keyNum] = 0; } if (key == '`'){ for (int i = 0; i < offset.length; i++){ offset[i] = 0; amplify[i] = 1; maximum[i] = 0; scaledMaximum[i] = 0; } } if (key == 'w'){ fft.window(FFT.HAMMING); } if (key == 'e'){ fft.window(FFT.NONE); } if (key == 'a'){ toggleEffect(alphaFilter); } if (key == 'b'){ toggleEffect(betaFilter); } } //Toggle effects such as notch or lowpass filter, not being used at //the moment, though. void toggleEffect(AudioEffect effect){ if(in.hasEffect(effect)){ in.removeEffect(effect); timeScale = normalScale; } else{ in.addEffect(effect); timeScale = alphaScale; } } //Draw the signal in time and frequency. void drawSignalData(){ timeDomainAverage = 0; for(int i = 0; i < windowLength - 1; i++) { stroke(255,255,255); //data that fills our window is normalized to +-1, so we want to throw out //sets that have data that exceed this by the factor absoluteCutoff if (abs(in.left.get(i*round(in.bufferSize()/windowLength)))*timeScale/normalScale > .95){ absoluteBadDataFlag = true; fill(250,250,250); stroke(150,150,150); } //Draw the time domain signal. line(i, 50 + in.left.get(i*round(in.bufferSize()/windowLength))*timeScale, i+1, 50 + in.left.get((i+1)*round(in.bufferSize()/windowLength))*timeScale); timeDomainAverage += abs(in.left.get(i*round(in.bufferSize()/windowLength))); //Draw un-averaged frequency bands of signal. if (i < (windowLength - 1)/2){ //set colors for each type of brain wave if (i <= round(3/scaleFreq)){ fill(0,0,250); //delta stroke(25,0,225); } if (i >= round(4/scaleFreq) && i <= round((alphaCenter - alphaBandwidth)/scaleFreq)-1){ fill(50,0,200); //theta stroke(75,0,175); } if (i >= round((alphaCenter - alphaBandwidth)/scaleFreq) && i <= round((alphaCenter + alphaBandwidth)/scaleFreq)){ fill(100,0,150); //alpha stroke(125,0,125); } if (i >= round((alphaCenter + alphaBandwidth)/scaleFreq)+1 && i <= round((betaCenter-betaBandwidth)/scaleFreq)-1){ fill(150,0,100); //low beta stroke(175,0,75); } if (i >= round((betaCenter - betaBandwidth)/scaleFreq) && i <= round((betaCenter + betaBandwidth)/scaleFreq)){ fill(200,0,50); //midrange beta stroke(225,0,25); } if (i >= round((betaCenter + betaBandwidth)/scaleFreq)+1 && i <= round(30/scaleFreq)){ fill(250,0,0); //high beta stroke(255,0,10); } if (i >= round(32/scaleFreq)){ fill(240,240,240); //rest of stuff, mainly noise stroke(200,200,200); } if (i == round(60/scaleFreq)){ fill(200,200,200); //color 60 Hz a different tone of grey, stroke(150,150,150); //to see how much noise is in data } //draw the actual frequency bars rect(FFTrectWidth*i, FFTheight, FFTrectWidth*(i+1), FFTheight - fft.getBand(i)/10); } } //divide the average by how many time points we have timeDomainAverage = timeDomainAverage / (windowLength - 1); } //Give user textual information on data being thrown out and filter's we have active. void displayText(){ //show user when data is being thrown out text("absoluteBadDataFlag = " + absoluteBadDataFlag, windowLength - 200, 120); if (absoluteBadDataFlag == true) { println("absoluteBadDataFlag = " + absoluteBadDataFlag); println(counter); } text("averageBadDataFlag = " + averageBadDataFlag, windowLength - 200, 140); if (averageBadDataFlag == true) { println("averageBadDataFlag = " + averageBadDataFlag); println(counter); } //and when a filter is being applied to the data text("alpha filter is " + in.hasEffect(alphaFilter), windowLength - 200, 160); text("beta filter is " + in.hasEffect(betaFilter), windowLength - 200, 180); } //Compute and display averages for each brain wave for the past ~5 seconds. void displayFreqAverages(){ //show averages of alpha, beta, etc. waves for (int i = 0; i < 6; i++){ float avg = 0; //raw data for amplitude of section of frequency int lowFreq = 0; int hiFreq = 0; //Set custom frequency ranges to be averaged. if(i == 0){ lowFreq = 0; hiFreq = 3; fill(0,0,250); stroke(25,0,225); } if(i == 1){ lowFreq = 3; hiFreq = 7; fill(50,0,200); stroke(75,0,175); } if(i == 2){ lowFreq = alphaCenter - alphaBandwidth; hiFreq = alphaCenter + alphaBandwidth; fill(100,0,150); stroke(125,0,125); } if(i == 3){ lowFreq = 12; hiFreq = 15; fill(150,0,100); stroke(175,0,75); } if(i == 4){ lowFreq = betaCenter - betaBandwidth; hiFreq = betaCenter + betaBandwidth; fill(200,0,50); stroke(225,0,25); } if(i == 5){ lowFreq = 20; hiFreq = 30; fill(250,0,0); stroke(255,0,10); } //Convert frequencies we want to the actual FFT bands. Because of our //FFT parameters, these happen to be equal (each band has a 1 Hz width). int lowBound = fft.freqToIndex(lowFreq); int hiBound = fft.freqToIndex(hiFreq); //Scale the band number, because of the issue outlined at very beginning of //program. lowBound = round(lowBound/scaleFreq); hiBound = round(hiBound/scaleFreq); //get average for frequencies in range for (int j = lowBound; j
Answers
Please format your code. (select code and press the C button left to the image button).
Ok, a short answer, hope it helps: above setup import the libraries:
And declare those 2 objects:
In setup create them:
Then if you send in draw you will have a constant stream. I hope 60 fps is not to slow, else you have to make a Thread.
Then you need something like this:
The Typetag gives info of what is incoming. So ifs means integer, float string.
I hope this helps, i started to look into osc this evening cause i need it as well. Tomorrow i will know some more :)
I moved to the topic to a proper category. I reformatted the code, although it is a bit of mess because the highlighter is confused by block comments. I deleted a duplicate thread without answer. Avoid multiplying threads on the same topic.
To newcomers in this forum: read attentively these instructions