Help writing a visual code for deforming circle

Hey processing users!
My name is Thomas Ryan, im a live electronic musician, and im trying to program a music visualizer with processing. I have a decent amount of programming history, and have used processing to create several audio reactive programs.

Heres what i want to write:

a program that draws a red circle, but the circle is deformed by the audio.
By “deform” i mean it would look like its being pulled at a point like a rubber band.

in simplicity, i want to make a circle that “wiggles slowly” reacting to the audio.

the program will be used at live shows!

THANKS EVERYONE

1 Like

Hello Ryan,

Start here:
https://processing.org/tutorials/
https://processing.org/tutorials/sound/
https://processing.org/reference/libraries/sound/
https://processing.org/reference/noise_.html

You should be able to do this. :slight_smile:

hey!
Yeah, ive been going through these for a while now haha
what im trying to figure out is how i can draw a circle, and make it morph using a combination of sine waves and audio input.

i have a set of variables made that spit out floats that correspond to the audio analysis.

Just dont exactly know what to use to deform the shape.

My initial thought was to use the curve(); stuff and use curve tightness to make it move, but i couldn’t draw a clean circle with them

is it possible to make a line that morphs between a set of 2 vertices?

You may have to resort to some math for this.

x = rcos(theta)
y = r
sin(theta)

And manipulate variables.

ill give that a crack, though i just stumbled across this https://processing.org/examples/morph.html

maybe i can take this and add a control on how much it morphs?

2 Likes

This is not the best demo but I took a lot of existing code and mashed it all together at the time:

It got one dislike. Maybe not a Stones fan. :slight_smile:

I may want to revisit this again…

Also check out the libraries in Processing:

Future:
https://processing.org/tutorials/pshape/
https://processing.org/examples/rgbcube.html

There was some discussion of this here recently:


I am having some fun with these and may post something in gallery in future.

Look forward to seeing your creative work.

:slight_smile:

2 Likes

Here is what ive got currently
working on making audio reactivity smoother, and trying to figure out hot to make those ellipses draw lines . between instead of be a bunch of circles

int xspacing = 8;   // How far apart should each horizontal location be spaced
int w;              // Width of entire wave
int maxwaves = 4;   // total # of waves to add together

float theta = 0.0;
float[] amplitude = new float[maxwaves];   // Height of wave
float[] dx = new float[maxwaves];          // Value for incrementing X, to be calculated as a function of period and xspacing
float[] yvalues;   


import processing.sound.*;
AudioIn in;
Amplitude amp;


// Global variables
float radius = 150; // Size of the circle
int numPoints = 127; // Number of points on the circe
float angle=TWO_PI/(float)numPoints; // Calculate the angle each point is on
float[][] xyArray; // Declare an array

void setup(){
  smooth();
  strokeWeight(1);
  size(1000,1000);// Window width
  background(0);
  //colorMode(RGB, 255, 255, 255, 100);
  frameRate(30);
  amp = new Amplitude(this);
   in = new AudioIn(this, 0);
  //in.play();
   amp.input(in);
  
  w = width + 16;
  
  
  
  
  for (int i = 0; i < maxwaves; i++) {
    amplitude[i] = random(3,10);
    float period = random(100,300); // How many pixels before the wave repeats
    dx[i] = (TWO_PI / period) * xspacing;
  }
  
  
  yvalues = new float[w/xspacing];
  
  
  
  
  
  // CREATE A LIST OF x & y CO-ORDINATES
  xyArray = new float [numPoints][3]; // Setup the array dimentions
  for(int i=0;i<numPoints;i++) { 
    float x = radius*sin(angle*i)+width/2;
    float y = radius*cos(angle*i)+height/2;
    xyArray[i][0] = x; // Store the x co-ordinate
    xyArray[i][1] = y; // Store the x co-ordinate
    xyArray[i][2] = 0.0;
  }
}

void draw(){     
  // Draw the shape
  background(0);
  
  
  
  calcWave();
  
  renderWave();
  
}

void calcWave() {
  // Increment theta (try different values for 'angular velocity' here
  theta += 0.02;

  // Set all height values to zero
  for (int i = 0; i < yvalues.length; i++) {
    yvalues[i] = 0;
  }
 
  // Accumulate wave height values
  for (int j = 0; j < maxwaves; j++) {
    float x = theta;
    for (int i = 0; i < yvalues.length; i++) {
      // Every other wave is cosine instead of sine
      if (j % 2 == 0)  yvalues[i] += sin(x)*amplitude[j];
      else yvalues[i] += cos(x)*amplitude[j];
      x+=dx[j];
    }
  }
}

void renderWave() {
  
  
  
  
  // A simple way to draw the wave with an ellipse at each location
  noStroke();
  fill(255,0,0);
  ellipseMode(CENTER);
   for(int i=0;i<numPoints;i++){ 
    float x2 = xyArray[i][0];
    float y2 = xyArray[i][1];
    strokeWeight(1);
    
    float ampp =  amp.analyze() ;
    ellipse(x2 , y2 + (yvalues[i] * ampp ) -50, 5, 5);
  }
  for (int x = 0; x < yvalues.length; x++) {
    
    
   
    
    //ellipse(x*xspacing,height/2+yvalues[x],16,16);
  }
}
1 Like

oops that didnt work well

int xspacing = 8;   // How far apart should each horizontal location be spaced
int w;              // Width of entire wave
int maxwaves = 4;   // total # of waves to add together

float theta = 0.0;
float[] amplitude = new float[maxwaves];   // Height of wave
float[] dx = new float[maxwaves];          // Value for incrementing X, to be calculated as a function of period and xspacing
float[] yvalues;   


import processing.sound.*;
AudioIn in;
Amplitude amp;


// Global variables
float radius = 150; // Size of the circle
int numPoints = 127; // Number of points on the circe
float angle=TWO_PI/(float)numPoints; // Calculate the angle each point is on
float[][] xyArray; // Declare an array

void setup(){
  smooth();
  strokeWeight(1);
  size(1000,1000);// Window width
  background(0);
  //colorMode(RGB, 255, 255, 255, 100);
  frameRate(30);
  amp = new Amplitude(this);
   in = new AudioIn(this, 0);
  //in.play();
   amp.input(in);
  
  w = width + 16;
  
  
  
  
  for (int i = 0; i < maxwaves; i++) {
    amplitude[i] = random(3,10);
    float period = random(100,300); // How many pixels before the wave repeats
    dx[i] = (TWO_PI / period) * xspacing;
  }
  
  
  yvalues = new float[w/xspacing];
  
  
  
  
  
  // CREATE A LIST OF x & y CO-ORDINATES
  xyArray = new float [numPoints][3]; // Setup the array dimentions
  for(int i=0;i<numPoints;i++) { 
    float x = radius*sin(angle*i)+width/2;
    float y = radius*cos(angle*i)+height/2;
    xyArray[i][0] = x; // Store the x co-ordinate
    xyArray[i][1] = y; // Store the x co-ordinate
    xyArray[i][2] = 0.0;
  }
}

void draw(){     
  // Draw the shape
  background(0);
  
  
  
  calcWave();
  
  renderWave();
  
}

void calcWave() {
  // Increment theta (try different values for 'angular velocity' here
  theta += 0.02;

  // Set all height values to zero
  for (int i = 0; i < yvalues.length; i++) {
    yvalues[i] = 0;
  }
 
  // Accumulate wave height values
  for (int j = 0; j < maxwaves; j++) {
    float x = theta;
    for (int i = 0; i < yvalues.length; i++) {
      // Every other wave is cosine instead of sine
      if (j % 2 == 0)  yvalues[i] += sin(x)*amplitude[j];
      else yvalues[i] += cos(x)*amplitude[j];
      x+=dx[j];
    }
  }
}

void renderWave() {
  
  
  
  
  // A simple way to draw the wave with an ellipse at each location
  noStroke();
  fill(255,0,0);
  ellipseMode(CENTER);
   for(int i=0;i<numPoints;i++){ 
    float x2 = xyArray[i][0];
    float y2 = xyArray[i][1];
    strokeWeight(1);
    
    float ampp =  amp.analyze() ;
    ellipse(x2 , y2 + (yvalues[i] * ampp ) -50, 5, 5);
  }
  for (int x = 0; x < yvalues.length; x++) {

    //ellipse(x*xspacing,height/2+yvalues[x],16,16);
  }
}
2 Likes

Hi,

Can you format code please? Just highlight and use the “preformatted text button”.

Some things are lost in translation otherwise… like above. You can edit last post.

I see equations to circles!

:slight_smile:

I swapped sin() and cos() at beginning of code; circle “closes” better now.

Added some code to join points; could get rid of points too!
I had to declare ampp outside of loop so I could use it to close circle outside of loop.

int xspacing = 8; // How far apart should each horizontal location be spaced
int w; // Width of entire wave
int maxwaves = 4; // total # of waves to add together

float theta = 0.0;
float[] amplitude = new float[maxwaves]; // Height of wave
float[] dx = new float[maxwaves]; // Value for incrementing X, to be calculated as a function of period and xspacing
float[] yvalues;

import processing.sound.*;
AudioIn in;
Amplitude amp;

// Global variables
float radius = 150; // Size of the circle
int numPoints = 127; // Number of points on the circe
float angle=TWO_PI/(float)numPoints; // Calculate the angle each point is on
float[][] xyArray; // Declare an array

void setup() {
  smooth();
  strokeWeight(1);
  size(1000, 1000);// Window width
  background(0);
  //colorMode(RGB, 255, 255, 255, 100);
  frameRate(30);
  amp = new Amplitude(this);
  in = new AudioIn(this, 0);
  //in.play();
  amp.input(in);

  w = width + 16;

  for (int i = 0; i < maxwaves; i++) {
    amplitude[i] = random(3, 10);
    float period = random(100, 300); // How many pixels before the wave repeats
    dx[i] = (TWO_PI / period) * xspacing;
  }

  yvalues = new float[w/xspacing];

  // CREATE A LIST OF x & y CO-ORDINATES
  xyArray = new float [numPoints][3]; // Setup the array dimentions
  for (int i=0; i<numPoints; i++) {
    float x = radius*cos(angle*i)+width/2;
    float y = radius*sin(angle*i)+height/2;
    xyArray[i][0] = x; // Store the x co-ordinate
    xyArray[i][1] = y; // Store the x co-ordinate
    xyArray[i][2] = 0.0;
  }
}

void draw() {
  // Draw the shape
  background(0);

  calcWave();

  renderWave();
}

void calcWave() {
  // Increment theta (try different values for ‘angular velocity’ here
  theta += 0.02;

  // Set all height values to zero
  for (int i = 0; i < yvalues.length; i++) {
    yvalues[i] = 0;
  }

  // Accumulate wave height values
  for (int j = 0; j < maxwaves; j++) {
    float x = theta;
    for (int i = 0; i < yvalues.length; i++) {
      // Every other wave is cosine instead of sine
      if (j % 2 == 0) yvalues[i] += sin(x)*amplitude[j];
      else yvalues[i] += cos(x)*amplitude[j];
      x+=dx[j];
    }
  }
}

float ampp;
void renderWave() {

  // A simple way to draw the wave with an ellipse at each location
  noStroke();
  fill(255, 0, 0);
  ellipseMode(CENTER);
  for (int i=0; i<numPoints; i++) {
    float x2 = xyArray[i][0];
    float y2 = xyArray[i][1];
    strokeWeight(1);

    ampp =  amp.analyze() ;
    ellipse(x2, y2 + (yvalues[i] * ampp ) -50, 5, 5);
    
    strokeWeight(3);
    stroke(255, 255, 0);
    if (i<numPoints-1)
    line(xyArray[i][0], xyArray[i][1]+yvalues[i] * ampp , xyArray[i+1][0], xyArray[i+1][1] + (yvalues[i+1] * ampp)) ;  
    }
    line(xyArray[numPoints-1][0], xyArray[numPoints-1][1]+yvalues[numPoints-1] * ampp , xyArray[0][0], xyArray[0][1] + (yvalues[0] * ampp)) ; 
  
  for (int x = 0; x < yvalues.length; x++) {

    //ellipse(x*xspacing,height/2+yvalues[x],16,16);
  }
}

That was fun! I am getting interested in using the sound library again.
I am experimenting with my RGB cube and assigning variables to vertices to manipulate.

:slight_smile:

2 Likes

hey!
thanks for those additions!
I added some code to make it more responsive to the low end and not as much the highs, and some easing!

int xspacing = 8;   // How far apart should each horizontal location be spaced
int w;              // Width of entire wave
int maxwaves = 2;   // total # of waves to add together

float theta = 0.0;
float[] amplitude = new float[maxwaves];   // Height of wave
float[] dxx = new float[maxwaves];          // Value for incrementing X, to be calculated as a function of period and xspacing
float[] yvalues;   
LowPass lowPass;
float xe;
float ye;
float easing = 0.65;




import processing.sound.*;
AudioIn in;
Amplitude amp;


// Global variables
float radius = 200; 
int numPoints = 127; 
float angle=TWO_PI/(float)numPoints; 
float[][] xyArray; 

float radius2 = 10;
int numPoints2= 127;
float angle2=TWO_PI/(float)numPoints2;
float[][] xyArray2;



void setup() {
 
  smooth();
  strokeWeight(1);
fullScreen();
  background(0);
  //colorMode(RGB, 255, 255, 255, 100);
  frameRate(30);
  amp = new Amplitude(this);
  in = new AudioIn(this, 0);
  //in.play();
   lowPass = new LowPass(this);
    lowPass.process(in, 500);
  amp.input(in);
 

  w = width + 20;





  for (int i = 0; i < maxwaves; i++) {
    amplitude[i] = random(3, 10);
    float period = random(240, 700); // How many pixels before the wave repeats
    dxx[i] = (TWO_PI / period) * xspacing;
  }


  yvalues = new float[w/xspacing];





  // CREATE A LIST OF x & y CO-ORDINATES
  xyArray2 = new float [numPoints2][3]; // Setup the array dimentions
  for (int i=0; i<numPoints2; i++) { 
    float x = radius2*cos(angle2*i)+width/2;
    float y = radius2*sin(angle2*i)+height/2;
    xyArray2[i][0] = x; // Store the x co-ordinate
    xyArray2[i][1] = y; // Store the x co-ordinate
    xyArray2[i][2] = 0.0;
  }
  
  
   xyArray = new float [numPoints][3]; // Setup the array dimentions
  for(int i=0;i<numPoints;i++) { 
    float x = radius*cos(angle*i)+width/2;
    float y = radius*sin(angle*i)+height/2;
    xyArray[i][0] = x; // Store the x co-ordinate
    xyArray[i][1] = y; // Store the x co-ordinate
    xyArray[i][2] = 0.0;
  }
}
  
  


void draw() {     
  // Draw the shape
  background(0);



  calcWave();

  renderWave();
}

void calcWave() {
  // Increment theta (try different values for 'angular velocity' here
  
  float ampp =  amp.analyze() * 10;

float targetX = ampp;
  float dx = targetX - xe;
  xe += dx * easing;
  theta += (0.01 + (ampp/3));

  // Set all height values to zero
  for (int i = 0; i < yvalues.length; i++) {
    yvalues[i] = 0;
  }

  // Accumulate wave height values
  for (int j = 0; j < maxwaves; j++) {
    float x = theta;
    for (int i = 0; i < yvalues.length; i++) {
      // Every other wave is cosine instead of sine
      if (j % 2 == 0)  yvalues[i] += sin(x)*amplitude[j];
      else yvalues[i] += cos(x)*amplitude[j];
      x+=dxx[j];
    }
  }
}



void renderWave() {




  // A simple way to draw the wave with an ellipse at each location
  noStroke();
  fill(255, 0, 0);
  ellipseMode(CENTER);
  
  
  float ampp =  amp.analyze() * 10;

float targetX = ampp;
  float dx = targetX - xe;
  xe += dx * easing;
  
  
  for (int i=0; i<numPoints; i++) { 
    float x3 = xyArray2[i][0];
    float y3 = xyArray2[i][1];
    
    float x2 = xyArray[i][0];
    float y2 = xyArray[i][1];
    strokeWeight(1);


float vals= abs(yvalues[i]);
    
    //ellipse(x2  , y2 - (yvalues[i] * (xe *10) ) -50, 5, 5);
    
    
     strokeWeight(6);
    stroke(255, 0, 0);
    if (i<numPoints-1)
    line(xyArray[i][0], xyArray[i][1]- (yvalues[i] * (xe *10) ) , xyArray[i+1][0], xyArray[i+1][1] - (yvalues[i] * (xe *10) )) ;  
    
    
    
  }
  //xe += dx * easing;
   line(xyArray[numPoints-1][0], xyArray[numPoints-1][1]+yvalues[numPoints-1] * (xe *10)  , xyArray[0][0], xyArray[0][1] - (yvalues[0] * (xe *10) )) ; 
  for (int x = 0; x < yvalues.length; x++) {




    //ellipse(x*xspacing,height/2+yvalues[x],16,16);
  }
}

The lines were not joining and I was trying to understand why.
To troubleshoot visually:
I bypassed easing
Added two yellow dots for end points.
A green line for the join of the end points.

I will leave this with you to debug.

You also had a + yvalues[numPoints and the other three are - yvalues[numPoints

//************
xe = 1/10f; // To bypass easing

strokeWeight(5);
stroke(255, 0, 0);
if (i<numPoints-1)
line(xyArray[i][0], xyArray[i][1]- (yvalues[i] * (xe *10) ) , xyArray[i+1][0], xyArray[i+1][1] - (yvalues[i] * (xe *10) )) ;  

}
//xe += dx * easing;
stroke(0, 255, 0);
line(xyArray[numPoints-1][0], xyArray[numPoints-1][1]-yvalues[numPoints-1] * (xe *10) , xyArray[0][0], xyArray[0][1] - (yvalues[0] * (xe *10) )) ;

stroke(255, 255, 0);
point(xyArray[numPoints-1][0], xyArray[numPoints-1][1]-yvalues[numPoints-1] * (xe *10));
point(xyArray[0][0], xyArray[0][1] - (yvalues[0] * (xe *10) ));
//***********

:slight_smile:

1 Like

Hey there

I thought I’d have a go at this challenge.

The shapes are drawn like a spider web (press key 2 to reveal)
The smooth shape is drawn with curveVertexes. For a closed shape its unfortunately necessary to repeat the first three points.

This is the essential method for the shape.

drawFleck() {
        beginShape();

        // First connect all values
        for (let i = 0; i < this.angles.length; i++) {
            let v = circlePosition(this.angles[i], this.values[i]);
            curveVertex(v.x, v.y);

        };

        // Redo the first 3 values for a smooth shape
        for (let i = 0; i < 3; i++) {
            let v = circlePosition(this.angles[i], this.values[i]);
            curveVertex(v.x, v.y);
        };

        endShape();
    }

Heres a preview:
flecks

3 Likes

Returning to the morph base sketch concept:

https://processing.org/examples/morph.html

…you can demonstrate adding audio to the morph demo by changing a single line to add random noise:

vertex(v.x + random(-5,5), v.y + random(-5,5));

The concept is that each vertex is a combination of two things – its geometric postiion (a square, a circle, whatever) and its audio displacement. Create an ArrayList of current geometry vertices and another of target vertices to lerp towards – periodically load an new geometry into the target array, and now you have a morphing display (as in the starting morph sketch). This can be used for squircles – or any closed shape, really.

Now, for any geometry, add audio displacement at draw time. You can do clever things with the displacement by using the built-in PVector methods. For example, rather than adding random x,y, you can PVector.lerp() your geometry point into a display point that is shifted away from (or towards) the center of the sketch, creating radial displacement – or even make that “center” a bouncing ball, or track the mouse, etc–so audio displacement is mapped onto your base vertex geometry, but also interactive and/or the mapping changes over time.

  PVector center = new PVector(mouseX-width/2, mouseY-height/2);
  for (PVector v : morph) {
    PVector v2 = v.copy().lerp(center, random(-0.5, 0.5));
    vertex(v2.x, v2.y);
  }