Drawing circles with FBO (Circular Spectogram)

Hello guys! I’m trying to write a code which draws many circles. The circles should change their brightness accordingly to the loudness of a specific frequency band which gets communicated via OSC from a Max MSP patch. The tiny circles should move all together in a circular manner around the center of the picture. By moving they should leave a trail which creates a picture, kinda like a circular spectogram.
If I have less than 60 circles, everything goes fine and it looks really good.
I’m facing the problem though, that if I want to have more than 60-70 circles it’s beginning to lag and around a 100 circle it wont even move anymore. My goal is to have 512 circles.
I’d greatly appreciate any help or hints especially because I’m not quite sure if I’m using the FBO right or if it’s even the right approach for my code.
Thank you! :slight_smile:

void ofApp::setup(){
    ofBackground(60, 60, 30);
    ofSetFrameRate(25);
    
    gui.setup();
    gui.add(sineParam.set("SINE", 200.0, 0.0, 300.0));
    gui.add(cosineParam.set("COSINE", 200.0, 0.0, 300.0));
    gui.add(speedParam.set("SPEED", 0.5, 0.0, 3.0));
    

    
    fbo.allocate(ofGetWidth(), ofGetHeight());
    fbo.begin();
    ofClear(255, 255, 20);
    fbo.end();

    receiver1.setup(PORT);
}

//--------------------------------------------------------------
void ofApp::update(){
    sine = sin(ofGetElapsedTimef() * speedParam)  * 200;
    cosine = cos(ofGetElapsedTimef() * speedParam)  * 200;
    sine2 = sin(ofGetElapsedTimef() * speedParam)  * 160;
    cosine2 = cos(ofGetElapsedTimef() * speedParam)  * 160;
    
    
     for (int i = 0; i < resolution; i++)
    {
        sineArray[i] = (sin(ofGetElapsedTimef() * speedParam)  * 298) / ((i+1)+10); //
        cosArray[i] = (cos(ofGetElapsedTimef() * speedParam)  * 298) / ((i+1)+10); //

    }

    // check for waiting messages
    while(receiver1.hasWaitingMessages()){

        
        for (int i = 0; i < resolution; i++)
        {
            values[i] = m.getArgAsString(i);
        }

        // get the next message
        receiver1.getNextMessage(m);
    }
}

void ofApp::draw(){
    gui.draw();

    fbo.draw(0, 0);

   fbo.begin();
    ofSetColor(0, 0, 0, 1);

    for (int i = 0; i < resolution; i++)
    {
        
        ofSetColor(ofToFloat(values[i]));
        ofSetCircleResolution(10);
        ofDrawCircle(sineArray[i] + ofGetWidth()/2, cosArray[i]+ofGetHeight()/2, r);

    }
    fbo.end();

}

The relevant values from the header file:

        float value;
    int resolution = 60;
    int r = 2;
    string values[60];
    float sineArray[60];
    float cosArray[60];

ofGetElapsedTimef() can be a little slow if called inside a for loop. to speed things up, you can grab it at the top of update:

void ofApp::update(){
   float timef = ofGetElapsedTimef(); 
    sine = sin(timef* speedParam)  * 200;
    cosine = cos(timef * speedParam)  * 200;
    sine2 = sin(timef * speedParam)  * 160;
    cosine2 = cos(timef * speedParam)  * 160;
    
    
     for (int i = 0; i < resolution; i++)
    {
        sineArray[i] = (sin(timef .....

Thats a nice idea. I just tried it but it still dies at 100 circles. :pleading_face:

two other things – only call ofSetCircleResolution() once (in setup, for example) and not sure ofToFloat is needed.

if that doesn’t speed things up, feel free to upload a zip of the code, I’ll be happy to take a look

I’ll try that now! I cant upload it directly because Im a new user but here is a dropbox link to it:

Thank you! :slight_smile:

Well, the problem seems to be this snippet

 while(receiver1.hasWaitingMessages()){

        
        for (int i = 0; i < resolution; i++)
        {
            values[i] = m.getArgAsString(i);
        }

        // get the next message
        receiver1.getNextMessage(m);
    }

if i comment it out, the program runs smoothly. I still need it though :smiley:

Where is m declared?

Iirc strings eat up a lot of memory, can you getarg as int or float instead?

also one note about the while construction is it’s designed to go through as many OSC messages as possible per frame so you always have the newest info. If you don’t use while, it is possible that you develop something like a backlog and the data you are reading is old – so the longer the app runs it gets more out of sync. you can also reduce the frequency you are sending the data, and as @s_e_p says, probably a lot faster to send as floats and not have to parse strings. I’m less familiar with it but I also know OSC has a blob type for larger arrays of data.

Hey @Mate_Sipos I like some of the concepts in Zach’s last post:

  1. try a different data type; I wonder if a char would be faster than an string
  2. maybe try the blob approach
  3. limit the amount of data coming from the max//msp application; the rate could be determined by when the latency becomes noticeable

Also, you can use oF to lerp between values if needed. This won’t reduce the latency but it could help smooth the animation.

I also wonder if using a shader with a video stream might be faster than OSC. A 16 x 16 RGBA image would have 1024 unsigned chars. I’ve never tried this though.

Also you can draw stuff into an ofFbo each cycle; drawings will accumulate if the ofFbo isn’t cleared each time. Previous drawings can be faded by overdrawing (a rectangle) with a semi-transparent color (kinda like an alpha mask).