Rusty Trombone

The Muses of Ancient Greece are dead and gone, and I’ve discovered why.

The concept is simple: buttons for tones, distance sensor for modulation.

Schematic:

Code:

/* Name: Jan
   Project: Rusty Trombone

*/

// keeping track of button input pins
int buttonPins[] = {A1, A2, A4, A5};
int buttonRed = A1;
int buttonGreen = A2;
int buttonYellow = A4;
int buttonBlue = A5;

// distance sensor pins
int pinTrigger = 9;
int pinEcho = 8;

// buzzer pins
int buzzer = 12;

// keeping track of base tones {C, E, G, A}
float baseNotes[] = {262, 330, 392, 440};

//difference between semitones, for use with modulation
float semitone = 15;

float modulation = 0;
float inches;
int fret = 1;

void setup() {
  
  Serial.begin(9600);

  //initializing pins
  pinMode(buzzer, OUTPUT);
  
  pinMode(pinTrigger, OUTPUT);
  pinMode(pinEcho, INPUT);

  //setting the buttons to INPUT_PULLUP means i don't have to worry about pull down resistors clogging up my board
  pinMode(buttonRed, INPUT_PULLUP);
  pinMode(buttonGreen, INPUT_PULLUP);
  pinMode(buttonYellow, INPUT_PULLUP);
  pinMode(buttonBlue, INPUT_PULLUP);

}

void loop() {
  fret = 0;
  bool buttonPressed = 0;
  inches = getDistance();
  for (int i = 0; i < 20; i+=2) {
    fret++;
    if (inches < i) {
      modulation = semitone * fret;
      break;
    }
  }

  if (digitalRead(buttonRed) == LOW) {      //if the first key is pressed
    tone(buzzer, 262 + modulation); 
    Serial.println(inches);                 
  }
  else if (digitalRead(buttonGreen) == LOW) { //if the second key is pressed
    tone(buzzer, 330 + modulation);                   
  }
  else if (digitalRead(buttonYellow) == LOW) { //if the third key is pressed
    tone(buzzer, 392 + modulation);                    
  }
  else if (digitalRead(buttonBlue) == LOW) {
    tone(buzzer, 440 + modulation);
  }
  
  else {
    noTone(buzzer);                        //if no key is pressed turn the buzzer off
  }
}


float getDistance()
{
  float echoTime;                   //variable to store the time it takes for a ping to bounce off an object
  float calculatedDistance;         //variable to store the distance calculated from the echo time

  //send out an ultrasonic pulse that's 10ms long
  digitalWrite(pinTrigger, HIGH);
  delayMicroseconds(1);
  digitalWrite(pinTrigger, LOW);

  echoTime = pulseIn(pinEcho, HIGH);      //use the pulsein command to see how long it takes for the
                                          //pulse to bounce back to the sensor

  calculatedDistance = echoTime / 148.0;  //calculate the distance of the object that reflected the pulse (half the bounce time multiplied by the speed of sound)


  return calculatedDistance;              //send back the distance that was calculated
}

Evidence of My Crimes

Reflections: Code as is requires a lot of fine-tuning for the buzzer not to sound like it’s gently caressing a combine harvester. More specifically, changing the changes in tone from continuous to discrete kept the buzzing down. Tweaking the distance intervals at which the tone goes up or down a semitone keeps it from oscillating too much, as might changing how often the tone sounds. The equation for calculating distance from the sensor also has a lot of room for tuning, but I have not the hubris to claim to be a master of time nor space. Fun project though, had a blast.

Assignment 3: Double Trouble

This is a simplistic extension of the wall bouncing puzzle shown in last class. The goal is twofold: make the ball bounce in a third dimension, and make the ball duplicate.

Code:

let gCircleSizeMax = 60;
let gCircleSizeMin = 10;
let gXSpeed = 2;
let gYSpeed = 4;
let gZSpeed = 1;

let gCircleArray = [];
let circlesMade = 0;

class BouncingCircle {
  constructor(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID) {
    this.x = xpos;
    this.y = ypos;
    this.xSpeed = xSpeed;
    this.ySpeed = ySpeed;
    this.zSpeed = zSpeed;
    this.circleSize = circleSize;
    this.ID = ID;
  }
  //give ball speed
  update() {
    this.x += this.xSpeed;
    this.y += this.ySpeed;
    this.circleSize += this.zSpeed;
  }
  
  checkWallCollisions() {
    let r = this.circleSize / 2;
    if (this.x < r || this.x > width - r) {
      this.xSpeed = -this.xSpeed;
      
    }
    if (this.y < r || this.y > height - r) {
      this.ySpeed = -this.ySpeed;
    }
  }
  
  checkBounce() {
    if (this.circleSize <= gCircleSizeMin) {
      if (this.xSpeed > 0 || this.ySpeed > 0 ) {
        this.zSpeed = -99/100 * this.zSpeed;
        this.xSpeed = 99/100 * this.xSpeed;
        this.ySpeed = 99/100 * this.ySpeed;
        if (this.zSpeed > gZSpeed/2) {
          duplicate(this)
        }
        
      }
      else {
        //this.zSpeed = 0;
        //gCircleArray.splice(circle.ID, 1);
      } 
    }
    if (this.circleSize >= gCircleSizeMax) {
      this.zSpeed = -this.zSpeed;
    }
  }
  
  drawSelf() {
    fill(255);
    ellipse(this.x, this.y, this.circleSize, this.circleSize);
  }
  
}


function duplicate(circle) {
  //if (circlesMade < 4) {
  
    //if (random(100) > 50) {
      print("Double Trouble")

      let xpos = circle.x;
      if (xpos > width - gCircleSizeMax)
        xpos = width - gCircleSizeMax
      if (xpos < gCircleSizeMax)
        xpos = gCircleSizeMax

      let ypos = circle.y;
      if (ypos > height - gCircleSizeMax)
        ypos = height - gCircleSizeMax;
      if (ypos < gCircleSizeMax)
        ypos = gCircleSizeMax;

      let xSpeed = circle.ySpeed;
      let ySpeed = circle.xSpeed;
      let zSpeed = gZSpeed;
      let circleSize = gCircleSizeMin + 5;
      let ID = gCircleArray.length;

      let newCircle = new BouncingCircle(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID)

      gCircleArray.push(newCircle);
      print(gCircleArray);
      
      circlesMade++
    //}
  //}
  
  if (gCircleArray.length >= 25) {
    gCircleArray.splice(0, gCircleArray.length / 2)
  }
  
  
}

function setup() {

  gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0));
  
  createCanvas(400, 400);
  smooth();
}

function draw() {
  background(0);
  
  for (var i = 0; i < gCircleArray.length; i++) {
    gCircleArray[i].update();
    gCircleArray[i].drawSelf();
    gCircleArray[i].checkWallCollisions();
    gCircleArray[i].checkBounce();
  }
  
  if (gCircleArray.length == 0) {
    gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0));
  }
  
  circlesMade = 0
  
}

Sketch: