Pure Data and Processing - Dealing with Data Types

Hi everyone,

Long-time Pd user, fairly new to Processing.

I have built a 'visualization' sketch receiving Cartesian coordinate data sent from a Pd patch (Pure Data) via oscP5 (OSC). For the most part, the data from Pd is float data, until it reaches zero, then Processing thinks that it is dealing with an integer, yielding the error, 'ClassCastException: java.lang.Integer cannot be cast to java.lang.Float.' Is there a way around this without omitting the value 0 or 0.0 from this program?

Code is included below. Any advice would be greatly appreciated.

    
import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;

SoundObject one;
SoundObject two;
SoundObject three;
SoundObject four;
SoundObject five;
SoundObject six;
SoundObject center;

void setup() {
  
  size(900, 900);
  noStroke();
  smooth();
  oscP5 = new OscP5(this, 8080);
  frameRate(100);
  
  one = new SoundObject("/xpos1", "/ypos1", "/amp1", width/2, height/2, 100); //osc tags, pos, size
  two = new SoundObject("/xpos2", "/ypos2", "/amp2", width/2, height/2, 100); //osc tags, pos, size
  three = new SoundObject("/xpos3", "/ypos3", "/amp3", width/2, height/2, 100); //osc tags, pos, size
  four = new SoundObject("/xpos4", "/ypos4", "/amp4", width/2, height/2, 100); //osc tags, pos, size
  five = new SoundObject("/xpos5", "/ypos5", "/amp5", width/2, height/2, 100); //osc tags, pos, size
  six = new SoundObject("/xpos6", "/ypos6", "/amp6", width/2, height/2, 100); //osc tags, pos, size
  center = new SoundObject("/cx", "/cy", "/ca", width/2, height/2, 100); //osc tags, pos, size
  
  oscP5.addListener(one);
  oscP5.addListener(two);
  oscP5.addListener(three);
  oscP5.addListener(four);
  oscP5.addListener(five);
  oscP5.addListener(six);
  oscP5.addListener(center);
}


void draw() {
  
  background(51); 
  one.circle(); //Display ellipse
  two.circle(); //Display ellipse
  three.circle();
  four.circle();
  five.circle();
  six.circle();
  center.cpoint();
}

public class SoundObject implements OscEventListener { //class name

//#Instance variables 

  float r = random(0, 255); //defining data; fields or 'instance variables' for class
  float g = random(0, 255);
  float b = random(0, 255);
  float a = random(50, 255);
 
  color c_rand = color(r, g, b, a); //random color scheme for each object
 
  String x_tag; //passed to constructor - osc ids
  String y_tag;
  String amp_tag;
 
  float xpos_t;
  float ypos_t;
  float amp_t;
  
  float xpos_temp;
  float ypos_temp;
  float amp_temp;

//#Constructor

  SoundObject(String tempx, String tempy, String tempamp, float temp_xpos, float temp_ypos, float temp_amp) {
    
     x_tag =  tempx; //strings - osc tags - x
     y_tag = tempy; //- y
     amp_tag = tempamp; //- amp
     xpos_t = temp_xpos; //-init x from 'main'
     ypos_t = temp_ypos; //-init y from 'main'
     amp_t = temp_amp; //init amp from 'main'
  }


//#Methods
  void oscStatus(OscStatus theStatus) {
  println(theStatus); 
  }
  
 
  void oscEvent(OscMessage theOscMessage) { //values assigned through constructor
  

   if(theOscMessage.checkAddrPattern(x_tag)==true) {
  //if(theOscMessage.checkTypetag("f")) {
 // println("this is a float"); //check if pd passes 0.0 as int - it is this case! recasting/data type handling is needed!
      
    xpos_temp = theOscMessage.get(0).floatValue();
    xpos_t = map(xpos_temp, -5, 5, 0, width);
  //println(xpos_temp);
 
  } 
  
   if(theOscMessage.checkAddrPattern(y_tag)==true) {
    ypos_temp = theOscMessage.get(0).floatValue();
    ypos_t = map(ypos_temp, -5, 5, 0, height);
  //println(ypos_t);
  
  } 

    if(theOscMessage.checkAddrPattern(amp_tag)==true) {
    amp_temp = theOscMessage.get(0).floatValue();
    amp_t = map(amp_temp, 0, 5, 0, 50);
  //println(amp_t); 
 
  }  
  
  
}



void circle() { //simple circles
    
    fill(c_rand);
    ellipseMode(CENTER);
    ellipse(xpos_t, ypos_t, amp_t, amp_t);
  
  }
  
  
  
void rectangle() { //simple circles
    
    fill(c_rand);
    rectMode(CENTER);
    rect(xpos_t, ypos_t, amp_t, amp_t);
  
  }  
  

void cpoint() { //simple circles
    
    fill(c_rand);
    rect(xpos_t, ypos_t, 20, 20);
   
  }   
  
}
  
Tagged:

Answers

  • You coulda told us which line the Exception occurs.
    Also, I don't think it's safe to re-define the Java's root class Object! :-SS

  • edited June 2014

    Admittedly, the limitation may be with the way Pd is formatting data before it reaches Processing and not with a specific line of code in this sketch (although I could very well be wrong about that). The exception occurs when said data stream from Pd reaches a zero from within a range between -1.0 and +1.0. The zero is treated as an int by Processing which causes, I suspect, lines 80 through 94 to give out.

    With that said, I am sure there is probably a more effective way to code this and I am open to suggestions. ;)

    Is there a fancy way for Processing to recognize a change in data type and pass the incoming stream to another function that supports that change?

    I can include the a link to the Pd patch for anyone interested.

  • edited June 2014

    I don't think it's safe to re-define the Java's root class Object!

    Fair point. I renamed the class. Still having the same issue, though. Can some kind of recasting help?

  • edited June 2014

    I don't think there are any errors in such line: float xpos_temp = theOscMessage.get(0).floatValue();
    Method floatValue() is supposed to return either a float or a Float datatype.

    I'm suspicious that the ClassCastException happens inside floatValue() itself! :-?
    If it is so, a try/catch block could potentially fix that!
    So I've made a separate getOscFloat() method for the sole purpose of safely invoking floatValue().

    Here's the blueprint:

    // forum.processing.org/two/discussion/5640/
    // pure-data-and-processing-dealing-with-data-types
    
    import oscP5.*;
    import netP5.*;
    
    final class Osc implements OscEventListener {
      String x_tag = "/xpos1";
      float xpos_t = width>>1;
    
      void oscStatus(final OscStatus oscStatus) {
        println(oscStatus);
      }
    
      void oscEvent(final OscMessage oscMsg) {
        if (oscMsg.checkAddrPattern(x_tag))
          xpos_t = (getOscFloat(oscMsg.get(0)) + 1.0) * (width>>1);
      }
    
      float getOscFloat(final OscArgument oscArg) {
        try {
          return oscArg.floatValue();
        }
    
        catch (final ClassCastException e) {
          println(e);
          //return 0.0;
          return oscArg.intValue();
        }
      }
    
      float getOscFloatAlt(final OscArgument oscArg) {
        return (Object) oscArg instanceof Float?
        oscArg.floatValue() : oscArg.intValue();
      }
    }
    
  • edited June 2014
    float xpos_temp;
    Object o = theOscMessage.get(0);
    if (o instanceof Float)
    {
      xpos_temp = ((Float) o).floatValue();
    }
    else if (o instanceof Integer)
    {
      xpos_temp = ((Integer) o).intValue();
    }
    else
    {
      print("Unhandled data type: " + o + " (" + o.getClass().getSimpleName()) + ")");
      return; // Or other processing. Don't try to use xpos_temp there
    }
    

    Perhaps OSC tries to guess the type of the value depending on presence of decimal point (and other factors like exponents) and returns an object whose type depends on the formatting of the value.

    The code above (untested!) shows how to deal with data of unknown / variable type.

  • Hi, GoToLoop's and PhiLho's suggestions will work best in this case, I am just wondering if pd sends a 0 as int instead of a float (you could check this with reading the typetag)? type casting is handled better with an updated version of oscP5 though there is no compiled download available as of now - but you could compile from source if you want. With this version casting works like this:

    OscMessage m = new OscMessage("/test");
    m.add(1).add(2).add("Hello");
    int v1 = m.intValue(0);
    float v2 = m.floatValue(1);
    String v3 = m.stringValue(2);
    println(v1,v2,v3);
    
  • I am just wondering if pd sends a 0 as int instead of a float

    I think that is exactly what is happening! Thanks for the suggestions, all. I will try tomorrow and get back to you.

  • edited June 2014

    Gents,

    After throwing in a simple if statement to read the typetag...

    if(theOscMessage.checkTypetag("i")) {

    ...it is indeed an issue with data type formatting in pd (cannot treat 0.0 as float; it is treated as an integer - as I suspected). I can add a miniscule decimal value to the outgoing data stream to overcome this problem, but this is a horrible hack.

    Sojamo, I am keen to implement your suggestion. Can you (or anyone) point me in the direction on a quick 'howto' on compiling a library for Processing?

    In the meantime, I will also try GoToLoop's and PhiLho's suggestions. Thank you.

  • edited June 2014

    GoToLoop, the purpose of the 'width>>1' bit shift is a rather elaborate way to ensure a float value, yes?

    The try-catch method produces the following error:

    java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Float
    

    I'd be keen to get this approach to work, if possible.

  • edited June 2014

    ... the purpose of the 'width>>1' bit shift is...

    just a faster integer division by 2. That is, same as width/2.

    The try-catch method produces the following error:

    It's supposed to catch the Exception. I've left println(e); just to flag it's happened!

  • edited June 2014

    Thanks for the clarification. I guess I'm not entirely sure of the usage, though.

    (getOscFloat(oscMsg.get(0)) + 1.0) * (width>>1);

    It seems somewhat superfluous to me. I understand that it assigns some kind of float to 'xpos_t'. Re: try/catch, the sketch is catching and printing the exception as intended. Thanks for your help.

  • @signals_ here is the compiled and downloadable zip version of oscP5 2.0.1; download and put the oscP5 folder inside the libraries folder of your processing sketchbook (on osx this is ~/Documents/Processing/libraries).

  • edited June 2014

    Sorry for the delay.

    Perhaps OSC tries to guess the type of the value depending on presence of decimal point (and other factors like exponents) and returns an object whose type depends on the formatting of the value. The code above (untested!) shows how to deal with data of unknown / variable type.

    PhiLho, what you say seems to be correct, although I am not sure how you can assign an integer value to 'xpos_temp' when it has been declared as a float. Forgive me if I am overlooking something very simple. I fear I may have confused things by using 'Object' as a class name above and so I have since updated the sketch in the original post.

  • Sojamo,

    Thank you! oscP5 no longer recognizes 'OscStatus', correct? Otherwise, the library seems to be working fine. Please allow me some time to try out your type casting example.

    Ricky

  • edited June 2014

    The solution is always simpler than it would first appear! Simple datatype conversion. D'oh: http://processing.org/examples/datatypeconversion.html

    See lines 100++.

    import oscP5.*;
    import netP5.*;
    
    OscP5 oscP5;
    NetAddress myRemoteLocation;
    
    SoundObject one;
    SoundObject two;
    SoundObject three;
    SoundObject four;
    SoundObject five;
    SoundObject six;
    SoundObject center;
    
    void setup() {
    
      size(900, 900);
      noStroke();
      smooth();
      oscP5 = new OscP5(this, 8080);
      frameRate(100);
    
      one = new SoundObject("/xpos1", "/ypos1", "/amp1", width/2, height/2, 100); //osc tags, pos, size
      two = new SoundObject("/xpos2", "/ypos2", "/amp2", width/2, height/2, 100); //osc tags, pos, size
      three = new SoundObject("/xpos3", "/ypos3", "/amp3", width/2, height/2, 100); //osc tags, pos, size
      four = new SoundObject("/xpos4", "/ypos4", "/amp4", width/2, height/2, 100); //osc tags, pos, size
      five = new SoundObject("/xpos5", "/ypos5", "/amp5", width/2, height/2, 100); //osc tags, pos, size
      six = new SoundObject("/xpos6", "/ypos6", "/amp6", width/2, height/2, 100); //osc tags, pos, size
      center = new SoundObject("/cx", "/cy", "/ca", width/2, height/2, 100); //osc tags, pos, size
    
      oscP5.addListener(one);
      oscP5.addListener(two);
      oscP5.addListener(three);
      oscP5.addListener(four);
      oscP5.addListener(five);
      oscP5.addListener(six);
      oscP5.addListener(center);
    }
    
    
    void draw() {
    
      background(51); 
      one.circle(); //Display ellipse
      two.circle(); //Display ellipse
      three.circle();
      four.circle();
      five.circle();
      six.circle();
      center.cpoint();
    }
    
    
    public class SoundObject implements OscEventListener { //class name
    
    //#Instance variables 
    
      float r = random(0, 255); //defining data; fields or 'instance variables' for class
      float g = random(0, 255);
      float b = random(0, 255);
      float a = random(50, 255);
    
      color c_rand = color(r, g, b, a); //random color scheme for each object
    
      String x_tag; //passed to constructor - osc ids
      String y_tag;
      String amp_tag;
    
      int amp_int;
      int ypos_int;
      int xpos_int;
      float xpos_t;
      float ypos_t;
      float amp_t;
    
      float xpos_temp;
      float ypos_temp;
      float amp_temp;
    
    //#Constructor
    
      SoundObject(String tempx, String tempy, String tempamp, float temp_xpos, float temp_ypos, float temp_amp) {
    
         x_tag =  tempx; //strings - osc tags - x
         y_tag = tempy; //- y
         amp_tag = tempamp; //- amp
         xpos_t = temp_xpos; //-init x from 'main'
         ypos_t = temp_ypos; //-init y from 'main'
         amp_t = temp_amp; //init amp from 'main'
      }
    
    
    
    //#Methods
    //void oscStatus(OscStatus theStatus) {
    //  println(theStatus); 
    //}
    
    
    void oscEvent(OscMessage theOscMessage) { //values assigned through constructor
    
      if(theOscMessage.checkAddrPattern(x_tag)==true) {
      if(theOscMessage.checkTypetag("i")) {  
        xpos_int = theOscMessage.get(0).intValue();
        xpos_temp = float(xpos_int);
        xpos_t = map(xpos_temp, -5, 5, 0, width);
        println(xpos_temp);
    
      } 
    
    }
    
    if(theOscMessage.checkTypetag("f")) {
      if(theOscMessage.checkAddrPattern(x_tag)==true) {     
        xpos_temp = theOscMessage.get(0).floatValue();
        xpos_t = map(xpos_temp, -5, 5, 0, width);
        println(xpos_temp);
    
      }
    }
      if(theOscMessage.checkAddrPattern(y_tag)==true) {
      if(theOscMessage.checkTypetag("i")) {  
        ypos_int = theOscMessage.get(0).intValue();
        ypos_temp = float(ypos_int);
        ypos_t = map(ypos_temp, -5, 5, 0, width);
        println(ypos_temp);
    
      } 
    
    }
    
    if(theOscMessage.checkTypetag("f")) {
      if(theOscMessage.checkAddrPattern(y_tag)==true) {     
        ypos_temp = theOscMessage.get(0).floatValue();
        ypos_t = map(ypos_temp, -5, 5, 0, width);
        println(ypos_temp);
    
      }
    }
    
     if(theOscMessage.checkAddrPattern(amp_tag)==true) {
      if(theOscMessage.checkTypetag("i")) {  
        amp_int = theOscMessage.get(0).intValue();
        amp_temp = float(amp_int);
        amp_t = map(amp_temp, -5, 5, 0, width);
        println(amp_temp);
    
      } 
    
    }
    
    if(theOscMessage.checkTypetag("f")) {
      if(theOscMessage.checkAddrPattern(amp_tag)==true) {     
        amp_temp = theOscMessage.get(0).floatValue();
        amp_t = map(amp_temp, -5, 5, 0, width);
        println(amp_temp);
    
      }
    }
    
    
    
    }
    
    
    
    
    void circle() { //simple circles
    
        fill(c_rand);
        ellipseMode(CENTER);
        ellipse(xpos_t, ypos_t, amp_t, amp_t);
    
      }
    
    
    
    void rectangle() { //simple circles
    
        fill(c_rand);
        rectMode(CENTER);
        rect(xpos_t, ypos_t, amp_t, amp_t);
    
      }  
    
    
    void cpoint() { //simple circles
    
        fill(c_rand);
        rect(xpos_t, ypos_t, 20, 20);
    
    
      }   
    
    }
    

    This works but I'm sure there is a better way. Open to suggestions. Sojamo, I never did get your approach to work. Thank you all for you help. Here's a little video of the working sketch:

  • edited June 2014

    xpos_t = (getOscFloat(oscMsg.get(0)) + 1.0) * (width>>1);

    The statement above is a faster analogous calc to your old original using map():
    xpos_t = map(getOscFloat(oscMsg.get(0)), -1, 1, 0, width);

    Dunno why are you picking on it though. I only offered getOscFloat() method as a temporary fix!
    The rest of the sample is merely enough bogus code in order to be compiled & "run"! Since I don't have the hardware!

  • edited June 2014

    Re: try/catch, the sketch is catching and printing the exception as intended. Thanks for your help.

    Seems like you've found out another way and decided to use that instead: checkTypetag().
    I've made an alternate getOscFloat() using your new finding:

      float getOscFloat(final OscMessage oscMsg, final int idx) {
        return oscMsg.checkTypetag("f")?
        oscMsg.get(idx).floatValue() : oscMsg.get(idx).intValue();
      }
    

    And my sample code which merely demonstrates how to call the new getOscFloat().
    Adapt it to your own code if you wish to make it more compact: %%-

    // forum.processing.org/two/discussion/5640/
    // pure-data-and-processing-dealing-with-data-types
    
    import oscP5.*;
    import netP5.*;
    
    final class Osc implements OscEventListener {
      String x_tag = "/xpos1";
      float xpos_t = width>>1;
    
      void oscStatus(final OscStatus oscStatus) {
        println(oscStatus);
      }
    
      void oscEvent(final OscMessage oscMsg) {
        if (oscMsg.checkAddrPattern(x_tag))
          //xpos_t = (getOscFloat(oscMsg.get(0)) + 1.0) * (width>>1);
          xpos_t = (getOscFloat(oscMsg, 0) + 1.0) * (width>>1);
      }
    
      float getOscFloat(final OscArgument oscArg) {
        try {
          return oscArg.floatValue();
        }
    
        catch (final ClassCastException e) {
          println(e);
          //return 0.0;
          return oscArg.intValue();
        }
      }
    
      float getOscFloat(final OscMessage oscMsg, final int idx) {
        return oscMsg.checkTypetag("f")?
        oscMsg.get(idx).floatValue() : oscMsg.get(idx).intValue();
      }
    }
    
  • Dunno why are you picking on it though. I only offered getOscFloat() method as a temporary fix! The rest of the sample is merely enough bogus code in order to be compiled & "run"! Since i don't have the hardware!

    GoToLoop, I'm so sorry, I meant no disrespect! :) It's purely my own ignorance. I didn't realize that it was filler. Thanks for the additional suggestion. I will certainly give it a go!

  • Another little update on how this is coming along:

Sign In or Register to comment.