Creating an ArrayList of SinOsc objects, trouble with adding, removing, play sound and stop sound

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(){
  }
  
}

Hi! You described the desired behavior, but not the actual behavior. Could you mention what is not working?