We are about to switch to a new forum software. Until then we have removed the registration on this forum.
the sketch takes microphone input or song and display spectrum of frequency with time. each frame it generates new object containing PShape. the object rotate itself until it complete the loop and get removed. I use PShape because drawing in immediate mode I get 10 fps but this method I get constant 60 fps. I noticed this method barely use CPU resource but consume so much memory.
the object create and remove at constant rate but why memory consumption is not constant but varying between 2GB-3GB?.
Is using PShape a good method to draw this?
how to optimize the code so that it eat less memory?
import ddf.minim.analysis.FFT;
import ddf.minim.*;
ArrayList<Line> lines;
Minim minim;
AudioInput in;
//AudioPlayer in;
FFT fft;
float THRES = 3;
void setup() {
size(600, 600, P3D);
smooth(16);
frameRate(60);
lines = new ArrayList<Line>();
minim = new Minim(this);
// Microphone input
in = minim.getLineIn();
// Local file
//in = minim.loadFile("mySong.mp3");
//in.play();
//
fft = new FFT( in.bufferSize(), in.sampleRate() );
println("buffer size = " + in.bufferSize());
println("sample rate = " + in.sampleRate());
}
void draw() {
background(0);
fft.forward( in.mix );
Line line = new Line();
lines.add(line);
for (int i=lines.size()-1; i>=0; i--) {
Line l = lines.get(i);
l.render();
if (l.dead) lines.remove(i);
}
//draw frequency wave
stroke(255);
strokeWeight(1);
noFill();
pushMatrix();
translate(width/2, height/2);
beginShape();
for (int i=0; i<260; i++) {
float f = fft.getBand(i)*0.75;
f = constrain(f,0,60);
vertex(i-260, -f, i-260, -f);
vertex(i-260, f, i-260, f);
}
endShape();
popMatrix();
frame.setTitle(int(frameRate) + " fps");
}
class Line {
PShape s;
boolean dead = false;
int radius = 260;
float theta = 0;
float angVel = 0.15;
int startAng = 89;
Line() {
theta = startAng+1;
s = createShape(POINTS);
s.beginShape();
for (int i=0; i<=radius; i++) {
colorMode(HSB, 360, 100, 100, 100);
//float data = abs( in.mix.get(i) );
float data = fft.getBand(i+10);
float hue = map(data, 0, THRES, 220, 200);
float sat = map(data, 0, THRES, 100, 90);
float br = map(data, 0, THRES, 0, 100);
color c = color(hue, sat, br, 100);
s.stroke(c);
s.strokeWeight(1);
s.vertex(0, radius - i); // invert to draw from outside
colorMode(RGB, 255);
}
s.endShape();
}
void render() {
if (!dead) {
pushMatrix();
translate(width/2, height/2);
rotate(radians(theta));
shape(s);
popMatrix();
theta += angVel;
}
if (theta > 360+startAng+1) dead = true;
}
}
Answers
1. Because of PShape's memory leak. PShape objects don't get garbage collected, you basically can't delete them at runtime.
2. Using PShape objects is generally much faster than drawing shapes in immediate mode as they are utilizing VBOs (Vertex Buffer Objects) under the hood. But their memory leak makes them kind of useless in situation where you have to remove a lot of them. Anyhow, ignoring the memory leak, rendering many small PShapes is still not the best way to go, have a look at point 3.
3. Instead of using PShapes and drawing all frequency lines every frame, try to render only one line per frame to an PGraphics object and then, render the (rotated) PGraphics object on the screen. This should reduce the memory cost to a minimum and is actually much faster than rendering countless PShapes.
Try the following code:
Btw.: Great sketch, looks brilliant!
Thank you for taking your time answering all of my thread! now my potato ram can handle the sketch perfectly.
Haha :D
No problem!