Seamless frequency circle (FFT)

Hi all,

For the past couple of days I’ve been getting into FFT and music visualization. Wanting to make a smooth, circular display of frequencies, I managed to do that, using Minim/FFT, a linear grouping of frequencies, and by using curveVertex to make the vertices around the circle. There is one problem, however, which is that the closing of the circle becomes a straight line instead of a curve, which looks quite off. Here’s what I have so far:

import ddf.minim.analysis.*;
import ddf.minim.*;

Minim minim;  
AudioPlayer jingle;
FFT fftLin;

void setup()
{
  size(600, 600);

  minim = new Minim(this);
  jingle = minim.loadFile("jingle.mp3", 1024);
  jingle.loop();
  fftLin = new FFT( jingle.bufferSize(), jingle.sampleRate() );
  fftLin.linAverages( 32 );
}

void draw()
{
  background(0);
  noFill();
  stroke(255);
  strokeWeight(3);
  translate(width / 2, height / 2);

  fftLin.forward(jingle.mix);

  beginShape();

  for (int i = 0; i < fftLin.avgSize(); i++)
  {
    float angle = map(i, 0, fftLin.avgSize(), 0, 7);
    float amp = fftLin.getAvg(i);
    float r = map(amp, 0.2, 2, 150, 200);
    float x = r * cos(angle);
    float y = r * sin(angle);
    curveVertex(x, y);
    if (i < 26) {
    } else {
    }
  }

  endShape(CLOSE);
}

I am aware that properly closing curveVertex shapes is a quite common issue and I’ve read every single thread I could find about it, trying to get a grasp of how to fix it - but so far, to no avail. The only proper, complete way I came across, was in this thread by @jeremydouglass : https://github.com/processing/processing/issues/5962

I managed to adapt that piece of code into my own project, and it actually closes the circle in a smooth way, but all the vertices only keep increasing in size intead of “resetting” as with my solution above, to the point where the whole circle exceeds the frame.

I would be very grateful for any help! Thanks. :slight_smile:

1 Like

@jeremydouglass’ code from the thread linked above - and so far the only succesful attempt I’ve seen at making an organic shape with curveVertex that closes correctly:

/**
 * Closed curveVertex
 * 2019-12-17 Jeremy Douglass -- Processing 3.4
 * https://github.com/processing/processing/issues/5962
 */
ArrayList<PVector> vecs = new ArrayList<PVector>();
int segs = 50;

void setup() {
  size(400, 400);
  randomSeed(1);
  // populate closed curve points
  for (int i=0; i<segs; i++) {
    PVector v = new PVector(random(120, 180), 0);
    v.rotate(i/(float)segs * TWO_PI);
    vecs.add(v);
  }
}

void draw() {
  background(192);
  translate(width/2, height/2);
  line(0, 0, width/2, 0); // indicator line for wrap-around
  
  // draw shape
  beginShape();
  for (int i=0; i<vecs.size()+3; i++) {  // wrap around +3
    PVector v = vecs.get(i%vecs.size()); // wrap around
    curveVertex(v.x, v.y);
  }
  endShape(CLOSE);

  // animate data
  for (int i=0; i<vecs.size(); i++) {
    PVector v = vecs.get(i);
    v.setMag(v.mag()+random(-2, 2));
  }
}
1 Like

not sure if this is of any use but maybe you could try a different way to update the circle points? I did a similar thing on my app but mapped the x/y values manually and held them in an array of objects Id created (my points object), it looked a bit like this (i have removed a lot of the code to try to just show bits that might be relevant)…

Update code…

for (int i = 0; i < waveBuffer.length; i++) {

   offset = PApplet.map(waveBuffer[i], -1, 1, -workingWidth / localHeight, workingWidth / localHeight);
   angle = PApplet.map(i, 0, waveBuffer.length * 2, 0, PConstants.TWO_PI);

   points.get(i).location.x = (float) (((workingWidth - workingWidth * 0.1) + offset) * PApplet.cos(angle));
   points.get(i).location.y = (float) (((workingWidth - workingWidth * 0.1) + offset) * PApplet.sin(angle));  						
}

draw code…

beginShape();		
for (int i = 0; i < points.size() - 1; i++) {
  vertex(points.get(i).location.x, points.get(i).location.y);
}
endShape(PConstants.CLOSE);
1 Like

Thank you so much! While I couldn’t use your code directly, reading and understanding it made me figure out how to solve it - by updating the points with “vecs.get(i).x = r * cos(angle);”

IT WORKS! :smiley:

3 Likes