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.
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?
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);
}
}
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);
}
}
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.
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
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();
}
…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);
}