As the title says I’m trying to create an ArrayList of SinOsc objects.
When I click the mouse I want it to add a new SinOsc object to the ArrayList which will play a sine wave.
The sin wave will differ in frequency and amplitude based on its x and y location on the screen.
When I remove the SinOsc object from the ArrayList I want the sound to stop as well.
These sinOsc objects will also be dynamically moving around the screen based on Boids flocking behaviours that are already defined in this code.
So ideally when the mouse is clicked both a boid object (which will be displayed on the screen) and a SinOsc object will be created and the same ones removed when needed.
I nearly have it, but still having trouble making this work. Any help is appreciated!
//importing sine sound and declaring array
import processing.sound.*;
ArrayList<SinOsc> sine;
ArrayList<Boid> boids;
float globalScale = .91;
float eraseRadius = 20;
String tool = "boids";
// boid control
float maxSpeed;
float friendRadius;
float crowdRadius;
float avoidRadius;
float coheseRadius;
boolean option_friend = true;
boolean option_crowd = true;
boolean option_avoid = true;
boolean option_noise = true;
boolean option_cohese = true;
// gui crap
int messageTimer = 0;
String messageText = "";
void setup () {
size(700, 700); //3508 pixels x 4961 1754x2480 877, 1240 , just some sizes
textSize(16);
recalculateConstants();
boids = new ArrayList<Boid>();
//sine is new Arraylist with SinOsc sounds in it
sine = new ArrayList<SinOsc>();
}
void recalculateConstants () {
maxSpeed = 2.1 * globalScale;
friendRadius = 60 * globalScale;
crowdRadius = (friendRadius / 1.3);
avoidRadius = 90 * globalScale;
coheseRadius = friendRadius;
}
void draw () {
noStroke();
colorMode(HSB);
fill(0, 100);
rect(0, 0, width, height);
if (tool == "erase") {
noFill();
stroke(0, 100, 260);
rect(mouseX - eraseRadius, mouseY - eraseRadius, eraseRadius * 2, eraseRadius *2);
if (mousePressed) {
erase();
}
} else if (tool == "avoids") {
noStroke();
fill(0, 200, 200);
ellipse(mouseX, mouseY, 15, 15);
}
for (int i = 0; i <boids.size(); i++) {
Boid current = boids.get(i);
current.go();
current.draw();
}
}
void keyPressed () {
if (key == 'q') {
tool = "boids";
} else if (key == 'e') {
tool = "erase";
} else if (key == '-') {
globalScale *= 0.8;
} else if (key == '=') {
globalScale /= 0.8;
} else if (key == '1') {
option_friend = option_friend ? false : true;
} else if (key == '2') {
option_crowd = option_crowd ? false : true;
} else if (key == '3') {
option_avoid = option_avoid ? false : true;
} else if (key == '4') {
option_cohese = option_cohese ? false : true;
} else if (key == '5') {
option_noise = option_noise ? false : true;
}
recalculateConstants();
// screen shot
// if (key == 'p') {
// saveFrame("boidsMaster-######.png");
// }
}
String s(int count) {
return (count != 1) ? "s" : "";
}
String on(boolean in) {
return in ? "on" : "off";
}
void mousePressed () {
switch (tool) {
case "boids":
boids.add(new Boid(mouseX, mouseY));
//adding new sine object/ particle to arraylist
sine.add(new SinOsc());
//does not recognise play as a function
sine.play();
break;
}
}
void erase () {
for (int i = boids.size()-1; i > -1; i--) {
Boid b = boids.get(i);
if (abs(b.pos.x - mouseX) < eraseRadius && abs(b.pos.y - mouseY) < eraseRadius) {
boids.remove(i);
//remove sin particle from array
sine.remove(i);
//does not recognise stop as a function
sine.stop(i);
}
}
}
class Boid {
// main fields
PVector pos;
PVector move;
float shade;
ArrayList<Boid> friends;
// timers
int thinkTimer = 0;
Boid (float xx, float yy) {
move = new PVector(0, 0);
pos = new PVector(0, 0);
pos.x = xx;
pos.y = yy;
thinkTimer = int(random(10));
shade = random(255);
friends = new ArrayList<Boid>();
}
void go () {
increment();
wrap();
if (thinkTimer ==0 ) {
// update our friend array (lots of square roots)
getFriends();
}
flock();
pos.add(move);
}
void flock () {
PVector allign = getAverageDir();
PVector avoidDir = getAvoidDir();
PVector avoidObjects = getAvoidAvoids();
PVector noise = new PVector(random(2) - 1, random(2) -1);
PVector cohese = getCohesion();
allign.mult(1);
if (!option_friend) allign.mult(0);
avoidDir.mult(1);
if (!option_crowd) avoidDir.mult(0);
avoidObjects.mult(3);
if (!option_avoid) avoidObjects.mult(0);
noise.mult(0.1);
if (!option_noise) noise.mult(0);
cohese.mult(1);
if (!option_cohese) cohese.mult(0);
stroke(0, 255, 160);
move.add(allign);
move.add(avoidDir);
move.add(avoidObjects);
move.add(noise);
move.add(cohese);
move.limit(maxSpeed);
shade += (random(2) - 1) ;
shade = (shade + 255) % 255; //max(0, min(255, shade));
}
void getFriends () {
ArrayList<Boid> nearby = new ArrayList<Boid>();
for (int i =0; i < boids.size(); i++) {
Boid test = boids.get(i);
if (test == this) continue;
if (abs(test.pos.x - this.pos.x) < friendRadius &&
abs(test.pos.y - this.pos.y) < friendRadius) {
nearby.add(test);
}
}
friends = nearby;
}
PVector getAverageDir () {
PVector sum = new PVector(0, 0);
//int count = 0;
for (Boid other : friends) {
float d = PVector.dist(pos, other.pos);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < friendRadius)) {
PVector copy = other.move.copy();
copy.normalize();
copy.div(d);
sum.add(copy);
//count++;
}
//if (count > 0) {
// sum.div((float)count);
//}
}
return sum;
}
PVector getAvoidDir() {
PVector steer = new PVector(0, 0);
int count = 0;
for (Boid other : friends) {
float d = PVector.dist(pos, other.pos);
// If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)
if ((d > 0) && (d < crowdRadius)) {
// Calculate vector pointing away from neighbor
PVector diff = PVector.sub(pos, other.pos);
diff.normalize();
diff.div(d); // Weight by distance
steer.add(diff);
count++; // Keep track of how many
}
}
if (count > 0) {
//steer.div((float) count);
}
return steer;
}
PVector getAvoidAvoids() {
PVector steer = new PVector(0, 0);
//int count = 0;
return steer;
}
PVector getCohesion () {
PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all locations
int count = 0;
for (Boid other : friends) {
float d = PVector.dist(pos, other.pos);
if ((d > 0) && (d < coheseRadius)) {
sum.add(other.pos); // Add location
count++;
}
}
if (count > 0) {
sum.div(count);
PVector desired = PVector.sub(sum, pos);
return desired.setMag(0.05);
} else {
return new PVector(0, 0);
}
}
void draw () {
noStroke();
fill(255);
pushMatrix();
translate(pos.x, pos.y);
ellipse(0, 0, 5, 5);
popMatrix();
//these use the position of the boids to determine frequency, amplitude and pan
//float freqMy = map(pos.y,height,0,0,500);
//float ampMy = map(pos.y,0,height,0,1);
//float panMx = map(pos.x,0,width,-1,1);
//float add= 0;
sine.set(freqMy,ampMy,add,panMx);
}
// update all those timers!
void increment () {
thinkTimer = (thinkTimer + 1) % 5;
}
void wrap () {
pos.x = (pos.x + width) % width;
pos.y = (pos.y + height) % height;
}
}
class SinOsc {
SinOsc(){
}
}