Sending a varying number from processing using OSC

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 
Tagged:

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:

    import oscP5.*;
    import netP5.*;
    

    And declare those 2 objects:

    OscP5 oscP5;
    NetAddress myRemoteLocation;
    

    In setup create them:

     /* start oscP5, listening for incoming messages at port 12000 */
      oscP5 = new OscP5(this,12000);
      myRemoteLocation = new NetAddress("127.0.0.1",12000);
    

    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.

    oscP5.send("/test",new Object[] {new Integer("1"), new Float(2.0),"test string."}, myRemoteLocation);

    Then you need something like this:

    void oscEvent(OscMessage theOscMessage) {
      /* check if theOscMessage has the address pattern we are looking for. */  
      if(theOscMessage.checkAddrPattern("/test")==true) {
        /* check if the typetag is the right one. */
        if(theOscMessage.checkTypetag("ifs")) {
          /* parse theOscMessage and extract the values from the osc message arguments. */
          int firstValue = theOscMessage.get(0).intValue();  // get the first osc argument
          float secondValue = theOscMessage.get(1).floatValue(); // get the second osc argument
          String thirdValue = theOscMessage.get(2).stringValue(); // get the third osc argument
          print("### received an osc message /test with typetag ifs.");
          println(" values: "+firstValue+", "+secondValue+", "+thirdValue);
          return;
        }
      }
      println("### received an osc message. with address pattern "+
              theOscMessage.addrPattern()+" typetag "+ theOscMessage.typetag());
    }
    

    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

Sign In or Register to comment.