## 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.

### 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 = [];

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 (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);

//}
//}

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));
}