Gopika and Bhavicka’s Final Project: Eyes of Enakshi

Well, here it is. I’m back for one last documentation on the Intro to IM website, and what looks like it will be the last one of the semester. It feels like it’s been a while since I’ve done one of these. I promise I’ll try to be organised this time, use sub-headings and all.

Before I go ahead, this is Gopika’s documentation for 90% completion of our project. It might be interesting to look at the changes.

The Idea and Story

We wanted to make an interactive murder mystery game with Indian elements. We had already come up with our story by last time – a rich Indian businesswoman has been murdered in a town which seems to be convinced that Enakshi killed her. Enakshi is a supernatural creature of our own creation – based on the south Indian yakshis but employing subtler methods (her eyes of anger) to kill. However, she claims that she is not the one to do it – and it is up to you to find out the truth. We introduce a whole cast of characters including the dead woman’s young husband, his two siblings, his mother, the pujari (priest) of the temple and her dearest friend and her kid.

The Implementation

Early on, we had divided our work. Gopika would work on the main screen, introduction to the legend, interacting with Enakshi, and the wiring of the four clues (and figuring out the capacitance). I worked on the Morse code (and button), the character dialogue screens, the slider mechanism for choosing the killer and the two end screens. Most of these were incorporated into the main code by Gopika because she already had an established system for the buttons. We mostly used a legend variable which would increase or decrease based on the button pressings, and each different value of legend corresponded to a different thing. After that we worked on writing out and planning the clues together.

The Changes

After the user feedback we got from some players and also professor, we decided to change quite a few things and make our game simpler. First we decided to only have a one killer storyline (we were planning to make it randomised before). We also rethought the physical interaction of our clues. This was the game run-down:

  • Main game screen with About and Play
  • The Legend
  • Interaction with Enakshi (with red eyes this time)
  • Introduction of the murder and characters
  • Morse code (finally figured out without delay and incorporated as a single unit into the main code now)
  • Pressing a force sensor to act as a fingerprint scanner and gain access to the clues
  • Clue 1: Turning to the diary page figured out through Morse and rubbing your finger on the page to have it appear on screen (through capacitance)
  • Clue 2: Lifting a newspaper attached to a foam board covered in foil and kept on foil (breaking the digital switch)
  • Clue 3: Lifting a toy from a larger rectangular force sensor (courtesy my previous experience with soft toys and force sensors) so that the reading gives 0
  • Clue 4:  A mechanism where a few layers of tissue separate a card (backed with foil) and a base of aluminium foil, where keeping a heavy object on the edge completes the circuit and lifting it breaks it.
  • Final sliding screen – made the animation effect more pronounced, and had a clue log (discarded the character log idea as it was too much info dumping)
  • Which leads to the two ending screens – winning and losing – if you know, you know.

    Our new Enakshi image with wonderfully realistic red eyes

We also incorporated Shamma’s feedback and changed the main screen’s yellow highlights to white. And the biggest task of all – we had to make a control box and use buttons which would be easier for gameplay. After a lot of effort and truly ingenious tinkering (we had to use the sharp edges of the aluminium foil box for cutting), we were able to bring our conveniently blood splattered box to life. We also decided to use crime scene type evidence markers based on Professor’s feedback, and did a bit of decorating after that. The result was something we were really pleased with.

The result of blood, sweat and tears (not really I’m just being dramatic jk jk)

In the final show, we also got a monitor, speaker (we had added a game theme fittingly called ‘Tense Detective’ and winning and losing sounds), and a webcam to connect on the monitor so users wouldn’t have to switch between two physical screens. Though these all acted funky initially, we got them to all work in the end.

I am going to attach some photos of our Arduino circuits too but unfortunately we took the photos after it was already inside the box.

So yeah, it is a bit of a mess. But it should be easy enough to recreate it if we look at the code. Speaking of..

The Code

Since our code is very long, here is the github repo for it. It also has all the other visuals and sounds if you wanna take a look.

The Challenges

Like I already mentioned, everything we tried seemed to not work at first. Or it would be working one day and then not work the next, or not work when we incorporate it with the other clues. For example, the force sensors were messing with each other’s readings, and Gopika ended up finding that (void)analogRead(variable); before reading the actual variable could help. We used this but we never knew what worked in the end. Even the digital switches were very difficult to make fool proof, because we knew they had to be reset again and again for people to play. Even going through test runs was hard because of the length of the game, but in the end the final result was so worth it!

Final Showcase, Reflections and Funnies

We had sorted out all our problems by the final day and even printed a little nameplate of our own.

It was so so satisfying to see people finally play our game and figure out the killer – and a lot of times not. This is a fun game trailer style edit of some of our interactions during the showcase, with the beloved losing screen added this time.

Everyone who played seemed to really enjoy and be invested in it. A few notable funny/scared reactions came every time when

  • The legend video started moving
  • Enakshi through the fog
  • “I miss Mummy.”
  • The sliding screen animation
  • “Starting with you…” (for those who got to see it)

We were glad that the mother-in-law wasn’t the totally obvious choice and people were getting quite confused between her, the sister-in-law, and the husband. We even had some people choose the brother-in-law.

A few special mentions must go to Leo who kept insisting that it was the kid and almost made us change the choosing line-up, and to our green button. After so much time spent soldering our beautiful buttons, we didn’t account for the difference in their sizes and the green one ended up being a bit loose- and had the honour of being pushed through hard by a lot of people, starting with Fatima on our class in Monday. It was almost like she had predicted the future.

Overall this was a very rewarding and fun project to work on and it was great working with Gopika, I feel like our visions really aligned for this and it shows in the final product. We took on a lot and I am glad all our hard work was worth it. The showcase where people were loving our game was honestly the highlight of our Finals Week.

I can’t believe this semester and class is at its end now, I truly had such a great time and learnt so many new things, from Professor and also from the other people in the class. Everyone was really kind and helpful, and without much further ado I am going to sign off and wish everyone a great winter break.

Don’t worry, Enakshi is resting too.

For now.

Bobbing Melody

So finally, I present to you my magical, whimsical, and bobbing art piece that will let you make your own melody.  So here’s the Bobbing melody in action.

 

To explain the implementation, here is the Arduino circuit.

The potentiometer values are mapped to create a color wheel (the red knob) that will control the color of visualization in real-time. The values of the ultrasonic sensor fitted in the mysterious black box are mapped into the x-axis for visualization. So the hand position in front of the screen is the position of the new balls dropping from the top of the screen. In visualization, these balls bounce at the bottom of the screen and upon hitting the bottom, the color of the just hit ball changes to yellow to eventually later fade back into its original color.  The whole screen is divided into twenty-one different notes of a piano and the x position of the hit ball determines the corresponding note to play. The music for piano is implemented using MIDI library and using tools like sforzando and loopMIDI.

While this project was very challenging and frustrating at times to finish, I surely had a great time working on it.  I am really glad how it turned out. A lot of the parts, especially the visualization was a trial and error process. I played around with a lot of color schemes and the speed and frame rate, took a lot of time, but finalized on my current settings and I love it. I hope you enjoyed this too.  If time permits, I would love to work on this project more to have various different instruments and visualizations to create a whole tune using different musical instruments and different visualization. Surely, this project and the class have inspired me a lot creatively.

Below is the code for Processing and Arduino.

//PROCESSING
//Serial connection and sound
import processing.serial.*;
import themidibus.*;
MidiBus myBus;
Serial myPort;

//variables for color mapping
int count = 400;
float radToDeg = 180.0 / PI;
float countToRad = TWO_PI / float(count);
float currentcolor;
float Xslider;

boolean fade = false;

//array list for balls
ArrayList<Ball> balls;

//sounds 21
int[] pitches = {48,52,53,55,59,60,64,65,67,71,72,76,77,79,83,84,88,89,91,95,96};


void setup() {
  fullScreen();
  //size(800,600);
  noStroke();
  frameRate(54);
  
  //port communication
  String portname=Serial.list()[0];
  myPort = new Serial(this,portname,9600);
  
  //midibus 
  myBus = new MidiBus(this,-1,"loopMIDI Port");
  
  // Create an empty ArrayList (will store Ball objects)
  balls = new ArrayList<Ball>();
  
  
  //color mode
  colorMode(HSB,360,99,99);
    
}

void draw() {
  background(0,0,0);
  
  //adding new balls on screen
  if(fade == false){
    addBalls(1);
  }
  
  
  //display all balls in action
  for (int i = balls.size()-1; i >= 0; i--) { 
    Ball ball = balls.get(i);
    if(ball.colorhue != 0){
      ball.move();
    }
    if(ball.colorhue != 0){
      ball.display();
    }
    
    //if no motion or very away from slider, reduce their life
    if(ball.x <= Xslider-width/6|| ball.x >= Xslider+width/6 || fade==true){
      if(ball.life > 100){
        ball.life = 100;
      }
    }
    
    //sound and colorshift on bouncing back from bottom
    if(ball.y >= height){
      ball.colorhue = 60;
      int numsound = int(map(ball.x,0,width,0,19));
      if(numsound<0 || numsound>20){
        numsound = abs(numsound%21);
      }
      if(ball.life<100){
        myBus.sendNoteOn(0,pitches[numsound],50);
      }
      else{
        myBus.sendNoteOn(0,pitches[numsound],127);
      }
    }
    
    //set the color back to orignal
    if(ball.y < height-height/9){
      ball.colorhue = ball.originalhue;
    }
    
    //remove the balls from array with finished lives
    if (ball.finished()) {
      balls.remove(i);
    } 
  }
}


// A new set of x ball objects are added to the ArrayList
void addBalls(int count) {
  for(int i=0; i<count; i++){
    float randomS = random(0,10);
    float ballWidth = random(4,30);
    float xPos = random(Xslider-width/20, Xslider+width/20);
    float yPos = random(-20,0);
    float angle = currentcolor * countToRad;
    int hue = int(angle * radToDeg);
    balls.add(new Ball(xPos, yPos, ballWidth,randomS,hue));
  }
}

//Serial Communication
void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    
    int values[]=int(split(s,','));
    if (values.length==2){
      currentcolor = map(values[0],19,925,380,290);
      print(values[0]);
      print(",");
      println(values[1]);
      if(values[1]>150 && values[1]<3000){
        fade= false;
        Xslider= map(values[1],150,3000,width, 0);
      }
      else{
        fade = true;
      }
    }
  }
}


// Simple bouncing ball class

class Ball {
  
  float x;
  float y;
  float speed;
  float acceleration;
  float w;
  float life = 255;
  int colorhue;
  int originalhue;
  float drag;
  boolean bounced= false;
  
  Ball(float tempX, float tempY, float tempW, float tempS, int hue) {
    x = tempX;
    y = tempY;
    w = tempW;
    speed = tempS;
    colorhue = hue;
    originalhue = hue;
    acceleration = 0.3;
    drag = 0.99;
  }
  
  void move() {
    //add speed
    speed = speed + acceleration;
    speed = speed * drag;
    
    // Add speed to y location
    y = y + speed;
    
    // If ball reaches the bottom
    // Reverse speed
    if (y > height) {
      // Dampening
      speed = speed * -0.9;
      y = height;
      bounced = true;
    }
    
    if(bounced==true && y<=10){
      // Dampening
      speed = speed * -0.9;
      y = 10;
      bounced = false;
    }
  }
  
  boolean finished() {
    // Balls fade out
    life--;
    if (life < 0) {
      return true;
    } else {
      return false;
    }
  }
  
  void display() {
    // Display the circle
    if(colorhue == 0){
      fill(color(colorhue,0,99),life);
    }
    else{
      fill(color(colorhue,99,99),life);
    }
    ellipse(x,y,w,w);
  }
}  

//ARDUINO

int trigger_pin = 2;
int echo_pin = 3;
long distance, pulse_duration;
int starttime;

void setup() {
  Serial.begin(9600);
  pinMode(trigger_pin, OUTPUT);
  pinMode(echo_pin, INPUT);
  digitalWrite(trigger_pin, LOW);
  Serial.println("0,0");
}

void loop() {
  int sensor = analogRead(A0);
  digitalWrite(trigger_pin, HIGH);
  digitalWrite(trigger_pin, LOW);
  pulse_duration = pulseIn(echo_pin, HIGH);
  Serial.print(sensor);
  Serial.print(',');
  Serial.println(pulse_duration);
}

 

Curse Breakers! Final :D

It’s done, everyone !!!! I DID IT !!! I made a video game and it works wonderfully!!!

Aaaaand here’s how I did it!!

You can take a look at my previous posts  documenting my progress:
https://intro.nyuadim.com/2021/11/27/toomies-final-project-progress-jjk-video-game/
https://intro.nyuadim.com/2021/12/08/curse-breakers-user-testing-progress/

I’m not entirely sure where to start with this, but I’ll do my best to walk you through it!

Let’s go through the game mechanics first:

The object of the game is to shoot the ghosts or ‘curses’ and collect 5 fingers within the time limit to win!

As (I think) I mentioned in my previous posts, I made classes for the fingers, the curses and the bullets.

Here are the classes:

The curses:

class Curse {
  float curx, cury;
  float spx, spy;
  float curw, curh;
  boolean disp = true;

  Curse(float _curx, float _cury, float _spx, float _spy) {
    curx = _curx;
    cury = _cury;

    spx = _spx;
    spy = _spy;

    curw = 260;
    curh = 160;
  }

  void display() {
    if (disp) {
      image(leftghost, curx, cury, curw, curh);
    }
    // displays the enemies on screen
  }

  void move() {
    curx += spx;

    if (curx>width+200) {
      curx=0-100;
    }
  }
}// ghost class end

The curses have random x and y positions and they move at random speeds. Once they collide with Yuji (the character) they disappear and the player loses a life. (You start with 5 lives, and you can also lose a life when you allow the ghosts to go offscreen).  The curses also disappear when you shoot them. This class has two functions: display and move. Display shows the image if the boolean (disp) is true, and move makes the ghosts move in the x direction and come back on the left side of the screen if they leave the screen on the right.

This is the bullets class: (I have 2 in my code but they are essentially the same so I’ll only copy one onto here):

class Bullet {

  float posx, posy;
  float speed;
  float a; //acceleration
  float r;
  boolean disp = true;
  color col;

  Bullet(float _posx, float _posy, float _speed, float _a, color _col) {
    posx = _posx;
    posy = _posy;

    col = _col;

    speed = _speed;
    a = _a;
    r =50;
  }

  void display() {
    fill(col);
    if (disp) {
      circle(posx, posy, r);
    }
  }

  void move() {
    posx -= speed;
    speed += a;
  }

  float distance(float x, float y) {
    return dist(posx, posy, x, y);
  }


  boolean done() {
    // removing bullets once they leave the screen
    if (posx < 0-r) {
      return true;
    } else {
      return false;
    }
  }
}

The bullets have the same functions as the curses class, with the addition of a color argument in the constructor (since there are two types of bullets in the game , one for the fingers and the other for the curses).

There is a distance variable which measures the distance of each bullet, since the bullets are in an array list.

The boolean ‘done’ removes the bullets once they’re offscreen to save memory!

The ‘Sukuna’Class refers to the fingers, here it is:

class Sukuna {
  float posx, posy;
  boolean disp = true;
  float sizew, sizeh;
  float fingertimer;


  Sukuna(float _posx, float _posy) {
    posx = _posx;
    posy = _posy;

    sizew = 140;
    sizeh = 160;
  }


  void display() {
    if (disp) {
      image(finger, posx, posy, sizew, sizeh);
    }
  }
}

It only has a display function, which is exactly the same as the other classes display functions, since the finger doesn’t move on screen once it appears.

As for the main code, I’ll go through it bit by bit:

Here is my beginning code, which is mostly filled with initializing variables:

import ddf.minim.*;
Minim minim;
AudioPlayer powerup;
AudioPlayer theme;
AudioPlayer gameover;
AudioPlayer life;
AudioPlayer woosh;
AudioPlayer winsound;

import processing.serial.*;
Serial myPort;

int score = 0;
float analog;
float starttime;
int fingercount = 0;
int lives = 5;
float prevbullettime=0;
int yujix;
PImage yuji, yujishoot, yujiidle, logo, battlebg, leftghost, finger, win, lose;
PFont gamefont;
int direction = 1;
int yujiR = 70;
int ghostR =60;
int bulletR =40;
int fingerR =70;
int speed = 3;
float acc = .2;
float gamemode = 1;
float countdown=0;
float respawntimer=0;
float fingertimer;
boolean timerActivated = false;
ArrayList<Bullet> bullets;
ArrayList<SBullet> sbullets;
Curse[] curses;
Sukuna[] sukuna;

Here is my setup code:

void setup () {
  fullScreen(); 
  battlebg = loadImage("battlebg.png");
  battlebg.resize(displayWidth, displayHeight);
  translate((displayWidth-1425)/2, (displayHeight-780)/2 +100);
  
  yujix = width-100;
  yujiidle = loadImage("yujiidle.png");
  yujishoot= loadImage("yujishoot.png");
  logo = loadImage("logo.png");
 leftghost = loadImage("leftghost.png");
  finger = loadImage("finger.png");
  win = loadImage("win.jpg");
  lose = loadImage("losepic.png");

  bullets = new ArrayList<Bullet>();
  sbullets = new ArrayList<SBullet>();

  minim = new Minim(this);
  powerup =minim.loadFile("powerup.wav");
  theme = minim.loadFile("jjkop.wav");
  theme.loop();
  gameover = minim.loadFile("gameover.wav");
  life = minim.loadFile("life.wav");
  woosh = minim.loadFile("swoosh.wav");
  winsound = minim.loadFile("winsound.wav");



  gamefont = createFont("/Users/fatimaaljneibi/Library/Fonts/Anime Inept.otf", 32);
  imageMode(CENTER);
  textAlign(CENTER);

  //ghosts:
  curses = new Curse[8] ;
  for (int i = 0; i<curses.length; i++) {
    curses[i]= new Curse(0, random(200, height-200), random(2, 8), random(-5, 5) );
  }

  sukuna = new Sukuna[1] ;
  for (int i = 0; i<sukuna.length; i++) {
    sukuna[i]= new Sukuna(random(300, width-300), random(200, height-200));
    sukuna[i].disp = false;
  }

  //serial setup stuff :
  printArray(Serial.list());
  String portname=Serial.list()[17];
  println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');
}

I set the game to be in fullscreen,  loaded all my images and fonts, and called my classes ( there are 8 ghosts, 1 finger, and array lists for the bullets).  I ended up using Minim instead of the processing sound library, because I found it easier to use for my sounds to play once.

My void draw code has all 4 of my game screens, here’s the code for the starting screen:

// starting screen:
 if (gamemode == 1) {
   if (!theme.isPlaying()) {
     theme.rewind();
     theme.loop();
   }
   background(#728DC6);
   textFont(gamefont, 150);
   image(logo, width/2, height/2-270, 400, 200);
   fill(#1D194D);
   text("CURSE BREAKERS!", width/2, height/2-100);
   ////title ^^ instructions below
   textFont(gamefont, 40);
   text("-press the red button to start-", width/2, height/2);
   //personal note: might turn the controller instructions into an image
   text("help yuji kill the curses and collect sukuna's fingers!", width/2, height/2+60);
   text("use the slider to move yuji, the yellow button to attack", width/2, height/2+100);
   text("and the blue button to collect the fingers!", width/2, height/2+140);
   text("collect 5 fingers within the time limit to win!", width/2, height/2+190);
 } //start screen end

It’s mostly just instructional text and starting the theme song loop.  Here’s a screenshot of what it looks like in the game!

Here’s the main game code:

 //game screen:
  if (gamemode == 2) {
    background(battlebg);
    if (!theme.isPlaying()) {
      theme.loop();
    }
    image(yuji, yujix, analog, 140, 200);

    // respawn curses:
    if (timerActivated==true) {
      if (millis()>respawntimer ) {
        timerActivated = false;
        for (int i=0; i<curses.length; i++) {
          if (curses[i].disp == false) {
            curses[i].curx = random(-100, -10) ;
            curses[i].cury = random(200, height-200);
            curses[i].disp=true;
          }
        }
      }
    }
    if (timerActivated == false && gamemode == 2) {
      respawntimer = millis()+3000; // the curses reappear on screen
      timerActivated = true;
    }

    //collision detection:

    for (int i=0; i<curses.length; i++) {

      float d1 = dist(yujix, analog, curses[i].curx, curses[i].cury);
      if ( d1 <= ghostR + yujiR && curses[i].disp==true) {
        lives-= 1;

        life.rewind();
        life.play();

        curses[i].disp=false;  //subtracts a life from yuji when he gets in contact with a ghost and makes it disappear on contact
      }
      for (int j = bullets.size()-1; j >= 0; j--) {
        float d2 = bullets.get(j).distance(curses[i].curx, curses[i].cury);
        if ( d2 <= ghostR + bulletR && curses[i].disp==true) {
          curses[i].disp=false;
          bullets.get(j).disp=false;
          bullets.remove(j);
          score += 10;
          woosh.rewind();
          woosh.play();
        }
      }
    }

    //shooting the fingers:
    for (int i=0; i<sukuna.length; i++) {
      for (int j = sbullets.size()-1; j >= 0; j--) {
        float d2 = sbullets.get(j).distance(sukuna[i].posx, sukuna[i].posy);
        if ( d2 <= fingerR + bulletR && sukuna[i].disp==true) {
          sukuna[i].disp=false;
          sbullets.get(j).disp=false;
          sbullets.remove(j);
          fingercount += 1;
          powerup.rewind();
          powerup.play();
        }
      }
    }

    //scoreboard + timer:
    pushStyle();
    textAlign(LEFT);
    textFont(gamefont, 30);
    fill(255);
    text(" Fingers collected: " + fingercount, 0, 30);
    text(" Score: " + score, 0, 60);
    text(" Lives left: " + lives, 0, 90);
    countdown = 60 -int((millis()-starttime)/1000);
    text(" Time left: " + countdown, 0, 120);
    popStyle();

    // calling class functions for the curses + bullets:
    for (int i=0; i<curses.length; i++) {
      curses[i]. display();
      curses[i]. move();
    }

    for (int i = bullets.size()-1; i >= 0; i--) {
      Bullet bullet = bullets.get(i);
      bullet.display();
      bullet.move();
      if (bullet.done()) {
        bullets.remove(i);
        // removes the bullets from the arraylist once they leave the screen to save memory
      }
    }
    for (int i = sbullets.size()-1; i >= 0; i--) {
      SBullet sbullet = sbullets.get(i);
      sbullet.display();
      sbullet.move();
      if (sbullet.done()) {
        sbullets.remove(i);
        // removes the bullets from the arraylist once they leave the screen to save memory
      }
    }
//win condition:
    if (countdown<=0 && fingercount <5) {
      gamemode = 4;
      theme.pause();
      winsound.rewind();
      for (int i = sbullets.size()-1; i >= 0; i--) {
        sbullets.remove(i);
      }
      for (int i = bullets.size()-1; i >= 0; i--) {
        bullets.remove(i);
      }
      //lose condition 2: (if time runs out)
    } else if (countdown>=0 && fingercount == 5) {
      gamemode =3;
      theme.pause();
      for (int i = sbullets.size()-1; i >= 0; i--) {
        sbullets.remove(i);
      }
      for (int i = bullets.size()-1; i >= 0; i--) {
        bullets.remove(i);
      }
    }

    //finger mechanics:

    for (int i=0; i<sukuna.length; i++) {
      sukuna[i].display();
    }
    for (int i=0; i<sukuna.length; i++) {
      if (score % 100 ==0 && score >0) {
        fingertimer =3000+millis();
        sukuna[i].disp = true;
      }
      if (millis() > fingertimer) {
        sukuna[i].disp = false;
        fingertimer =0;
      }
    }
    // if the curses leave the screen without being shot, you lose 1 life
    for (int i=0; i<curses.length; i++) {
      if (curses[i].curx > width && curses[i].disp == true) {
        lives -= 1;
        life.rewind();
        life.play();
        curses[i].disp = false;
      }
    }

    // you lose if your lives are at 0
    if (lives <= 0) {
      gameover.rewind();
      gamemode = 4;
    }
  } // game screen end

There’s quite a lot going on here. The character is drawn here, with his Y position being the slider (analog input). We’ll go over the serial communication in a bit!

I made a respawn timer for the curses, basically the logic here is that if the curses disp = false ( i.e. they’re not visible on screen) and the current time > respawn timer, the curses will respawn at a new random height on screen, with the width being offscreen on the left, so they move forward to the right.

After that, there’s the code for collision detection. The logic here is that if the distance between the two objects is less than the sum of their radii (which are variables that I set at the very beginning of my code) then something happens! The code for what that ‘something’ is differs depending on what two objects they are. There’s collision detection for the bullets and the curses, and for the curses and yuji, and for the bullets and the fingers.

Then, there’s code for the scoreboard and the timer. You can see the scoreboard in the top left of this screenshot:
It has a finger counter(increases whenever you shoot a finger), a lives counter(starts at 5, decreases by one if Yuji gets hit by a ghost, or lets one get away), a score(based on the ghosts that you hit) and a timer! The timer is 60 seconds from the start of the game.

Following this code is the code to call class functions for the curses and bullets.

After this comes the code for win conditions. You can only win after collecting 5 of Sukuna’s fingers. A finger appears after you hit a score that’s divisible by 100, and it disappears after a few seconds if you don’t collect it in time! Once you win, you go to the winning screen!

To lose the game, you either lose all of your lives or you don’t collect 5 fingers by the time the timer ends! Once you lose, you are taken to the losing screen ><.

Then, we have the code for the finger mechanics! It’s pretty simple, I called the display function for the finger, and the disp boolean is initially false. It becomes true once you hit a score divisible by zero, and disappears shortly after.

The code following that is to decrease the lives variable by 1 every time a ghost leaves the screen.

Heres the winning and losing screen’s code, accompanied by screenshots of both in-game:

 // winning & losing screens:

  //win screen, score/time , sound effect:
  if (gamemode == 3) {
    theme.pause();
    winsound.play();
    background(#1D194D);
    textFont(gamefont, 100);
    fill(#728DC6);
    text("YOU WIN!", width/2, height-250);
    //title ^^   info below
    textFont(gamefont, 50);
    text("score:"+score, width/2, height-200);
    text("time left:"+countdown, width/2, height-150);
    text("fingers collected:"+ fingercount, width/2, height-100);

    textFont(gamefont, 40);
    text("-press the red button to try again!-", width/2, height-50);
    image(win, width/2, 250, 700, 400);
  }//win screen end

  if (gamemode == 4) {
    //losing screen, click to try again, sound effect
    theme.pause();
    gameover.play();

    background(#1D194D);
    textFont(gamefont, 100);
    fill(#728DC6);
    text("YOU LOSE:(", width/2, height-200);
    //title ^^   info below
    textFont(gamefont, 50);
    text("score:"+score, width/2, height-150);
    text("fingers collected:"+ fingercount, width/2, height-100);
    textFont(gamefont, 40);
    text("-press the red button to try again!-", width/2, height-50);
    image(lose, width/2, 300, 700, 400);
  }//losing screen end
}//draw bracket


Also, I’ve added various sound effects to the game, I’ll list them here:
A ‘whoosh’ sound when you shoot the curses
A powerup sound effect when you collect a finger
The theme song (which plays only during the start screen and the game screen)
A victory sound plays in the win screen
A game over sound plays on the lose screen

Here is the serial communications code:

Processing:

void serialEvent(Serial myPort) {
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  //int values = parseInt(s);
  //boolean shoottest = false;
  if (s!=null) {
    //println(s);
    int values[]=int(split(s, ','));

    // note: values: 0 = slider, 1= yellow, 2= blue, 3= red

    //slider:
    analog =map(values[0], 0, 1023, 100, height-70);
    yuji = yujiidle;
    //attacking (yellow) button:
    if (values[2] == 1 && gamemode == 2) {
      // not working:
      yuji = yujishoot;
      color Ccircle = color(#98F7FF, 150);
      noStroke();
      if (millis() - prevbullettime > 400) {
        bullets.add(new Bullet(width-150, analog+20, speed, acc, Ccircle));
        prevbullettime= millis();
      }
    }

    // start button:
    if (values[3] == 1 && gamemode == 1) {
      starttime=millis();
      fingercount = 0;
      score = 0;
      gamemode = 2;
      //replay : (red button)
    } else if (values[3] == 1 && gamemode == 3 || values[3] == 1 && gamemode ==4) {
      fingercount = 0;
      lives = 5;
      gamemode =1;
      delay(1000); // so you dont skip to the start screen too quickly after pressing the button
      for (int i=0; i<curses.length; i++) {
        curses[i].curx = random(-100, -10);
      }
    } //fingers (blue)
    if (values[1] == 1 && gamemode == 2) {
      yuji = yujishoot;
      color Scircle = color(#FF8B8B, 150);
      noStroke();
      if (millis() - prevbullettime > 400) {
        sbullets.add(new SBullet(width-150, analog+20, speed, acc, Scircle ));
        prevbullettime= millis();
      }
    }
    
  }

  myPort.write(int(0)+"\n");
}

Arduino:

int bluepin = 5;
int yellowpin = 3;
int redpin = 6;
int sliderpin = A5;

void setup() {
  pinMode(bluepin , INPUT);
  pinMode(yellowpin , INPUT);
  pinMode(redpin , INPUT);
  pinMode(sliderpin , INPUT);
  Serial.begin(9600);
  Serial.println("0,0,0,0");
}

void loop() {
  int bluebutton = digitalRead(bluepin);
  int yellowbutton = digitalRead(yellowpin);
  int redbutton = digitalRead(redpin);
  int slider = analogRead(sliderpin);

//checking if everything is connected properly:
//comment this out to run processing
//    Serial.print(bluebutton);
//    Serial.print(yellowbutton);
//    Serial.print(redbutton);
//    Serial.println(slider);

  while (Serial.available()) {
    int fromP = Serial.parseInt();

    if (Serial.read() == '\n') {
      Serial.print(slider);
      Serial.print(",");
      Serial.print(yellowbutton);
      Serial.print(",");
      Serial.print(bluebutton);
      Serial.print(",");
      Serial.println(redbutton);
    }

  }


}

I have 4 parts connected to my circuit: 3 buttons and a slider. I built a controller box out of foam to safely conceal my circuit while also making it easy for players to use! Here is my process making that:

It looked like this at first, but I spray painted it black afterwards and added a 3rd button! (the red one, to start playing the game. initially, you would use either the blue or yellow to start playing the game and switch between screens, but that wasn’t giving me great results, so I decided to add a third button)

the button in this image was tiny because I couldn’t find one that looks like my other two, thankfully I asked on discord and got one!! (thank you bhavicka!!)

Here’s the final product!

Aaaaaand that’s it! TA-DA!! I’m very proud of what I’ve learned and achieved in this course, I had lots of fun!! Thank you 🙂

This is a gameplay video of the final game!!
https://youtube.com/shorts/cLE6tk_7XO4?feature=share

 

[FINAL PROJECT] Smash It!/Smash Your Memory! (A Music Memory Game)

IDEA:

Setup: Five Pads on the floor and an interface.

Operations: The note pads correspond to the pentatonic C scale: C, D, E, G, A. As shown on the pads, they represent all the things I hate, I assume you too, the most throughout this semester. To win the game, you must recreate a melody by smashing the pads.

Symbols: The things I hate the most this semester

  • C note: COVID
  • D note: Deadlines
  • E note: course Enrollment
  • G note: GPA
  • A note: Anxiety

IMPLEMENTATION:

  1. Title Page
  2. Rules
  3. Practice: plays demo melody
  4. Test
  5. Win or Lose

video of im showcase:

Most people got it correct after 2-3 tries, around 3-5 succeeded on the first try (talk about music talents), and 3 people just gave up. People enjoyed it a lot more than I thought they would!

CODES:

//Processing Codes

/*
 name: Chi-Ting Tsai
 assignment: final project
 date: 12/07/2021
 "Smash It!" is a music memory game where player would be instructed to memorize a melody 
 and recreate it by stepping on the pads corresponding to notes on the pentatonic C scale.
 */

import processing.sound.*;
SoundFile demoMelody;
SoundFile recC;
SoundFile recD;
SoundFile recE;
SoundFile recG;
SoundFile recA;
SoundFile winning;
SoundFile losing;

int size = 200;
color frame = color(237, 168, 17);

int stage;
int noteC = 1;
int noteD = 2;
int noteE = 3;
int noteG = 5;
int noteA = 6;
int[] correctMelody = {noteD, noteC, noteE, noteG, noteA, noteG, noteD, noteC};

void setup() {
  size (displayWidth, displayHeight);
  background(color(99, 144, 130));
  String portname=Serial.list()[3];
  println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  demoMelody = new SoundFile (this, "/Users/chi-tingtsai/Downloads/5-seconds-of-silence_gcP1Vako.wav");
  recC = new SoundFile (this, "/Users/chi-tingtsai/Downloads/C.wav");
  recD = new SoundFile (this, "/Users/chi-tingtsai/Downloads/D.wav");
  recE = new SoundFile (this, "/Users/chi-tingtsai/Downloads/E.wav");
  recG = new SoundFile (this, "/Users/chi-tingtsai/Downloads/G.wav");
  recA = new SoundFile (this, "/Users/chi-tingtsai/Downloads/A.wav");
  winning = new SoundFile (this, "/Users/chi-tingtsai/Downloads/Winning Sound Effect.wav");
  losing = new SoundFile (this, "/Users/chi-tingtsai/Downloads/The Price is Right Losing Horn - Gaming Sound Effect (HD).wav");
}

void draw() {
  //scene change
  if (stage == 0) {
    rank();
  } else if (stage == 1) {
    rules();
  } else if (stage == 2) {
    practice();
  } else if (stage == 3) {
    game();
  } else if (stage == 4) {
    lose();
  } else if (stage == 5) {
    win();
  }
}
//Processing codes 

void rank() {
background(color(99, 144, 130));
PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
noStroke();
fill(255);
textAlign(CENTER);

textFont(F, 50);
text("Smash Your Memory!\nA Music Memory Game", width/2, height/2-50);
text("Smash C note(COVID) to Begin", width/2, height*3/4);

//frame
noStroke();
rectMode(CENTER);
fill(frame);
rect(width/2, 10, width, 20);
rect(width/2, height-60, width, 20);
rect(10, height/2, 20, height);
rect(width-10, height/2, 20, height);
}
//Processing 

void rules() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  //explain how to play
  textFont(F, 50);
  text("RULES: Memory Game", width/2, height/4);
  textFont(F, 30);
  text("INSTRUCTIONS:\n The note pads correspond to the pentatonic C scale: C,D,E,G,A.\n As shown on the pads, they represent all the things I hate,\nI assume you too, the most throughout this semester.\n To win the game, you must recreate a melody by smashing the pads.", width/2, height/2-120);
  textFont(F, 30);
  text("Smash Deadlines to play the melody ONCE(AND ONLY ONCE!) and practice!", width/2, height-200);
  
  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
//Processing Codes 

int i = 0;
char[] refMelody = {' ', ' ', ' ', 'D', 'C', 'E', 'G', 'A', 'G', 'D', 'C'};


void practice() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  //text
  textFont(F, 50);
  text("LISTEN CAREFULLY & PRACTICE (8 NOTES)", width/2, height/4);
  textFont(F, 30);
  text("Practice to familiarize with how the notes sound!\nRememer: your job is to smash the pads to recreate the melody!\n", width/2, height/2-120);
  textFont(F, 50);
  textFont(F, 50);
  text("Smash Space Bar to begin smashing!", width/2, height-170);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);

  //telling player which note it is
  if (frameCount%118 == 0 && i < 10) {
    i++;
  }
  text("Now playing: \n" + refMelody[i], width/2, height/2+75);
}
//Processing Codes

import processing.serial.*;
Serial myPort;

int aSignal = 0;
int prevASignal = 0;
int val = 0;

void game() {
  if (i == 10) {
    i = 0;
  }
  
  //background
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  textFont(F, 50);
  text("Listen Carefully and Recreate!", width/2, height/4);
  textFont(F, 30);
  text("The things I hate the most this semester\nC note: COVID\nD note: Deadlines\nE note: course Enrollment\nG note: GPA\nA note: Anxiety\n", width/2, height/2-80);
  fill(frame);
  textFont(F, 50);
  text(val + "/8" + " Notes Correct! Keep smashing!", width/2, height-170);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}

void serialEvent(Serial myPort) {
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!= null) {
    aSignal = parseInt(s);
    //scene transition
    if (stage == 0 && aSignal == noteC) {
      stage = 1;
      recC.play();
      val = 0;
    }
    if (stage == 1 && aSignal == noteD) {
      stage = 2;
      demoMelody.amp(0.8);
      demoMelody.play();
    }
    if ((stage == 4 || stage == 5) && aSignal == noteG) {
      stage = 0;
      recG.play();
    }

    //note playing and verification
    if ((stage == 2 || stage == 3) && prevASignal!= aSignal) {
      if (aSignal == noteC) {
        recC.play();
      } else if (aSignal == noteD) {
        recD.play();
      } else if (aSignal == noteE) {
        recE.play();
      } else if (aSignal == noteG) {
        recG.play();
      } else if (aSignal == noteA) {
        recA.play();
      }
      //verify note in array
      if (stage == 3 && aSignal != 0) {
        if (correctMelody[val] == aSignal) {
          val++;
          prevASignal = aSignal;
          if (val == 8) {
            delay(2000);
            stage = 5;
            winning.play();
          }
        } else {
          delay(2000);
          stage = 4;
          losing.amp(0.3);
          losing.play();
        }
      }
      prevASignal = aSignal;
    }
  }
  myPort.write('\n');
}

void keyReleased() {
  if (key == ' ' && stage == 2) {
    stage = 3;
    game();
  }
}
//Processing Codes

void lose() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);
  
  textFont(F, 50);
  text("Awwww... Smash GPA to play again.", width/2, height*3/4);
  text("Not the right note!\nYou've reached the " + (val) + "th note in the melody!", width/2, height/2-80);
  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
//Processing 

void win() {
  background(color(99, 144, 130));
  PFont F = createFont("TimesNewRomanPS-BoldMT", 1);
  noStroke();
  fill(255);
  textAlign(CENTER);

  textFont(F, 50);
  text("Congratulations! You have recreated the entire melody!", width/2, height/2);
  textFont(F, 50);
  text("Smash GPA to play again!", width/2, height/2+50);
  textFont(F, 30);
  fill(frame);
  text("Have you found your peace by smashing those that give off negative energy?", width/2, height/2-50);

  //frame
  noStroke();
  rectMode(CENTER);
  fill(frame);
  rect(width/2, 10, width, 20);
  rect(width/2, height-60, width, 20);
  rect(10, height/2, 20, height);
  rect(width-10, height/2, 20, height);
}
//Arduino codes 

//variable declaration
const int C = 1;
const int D = 2;
const int E = 3;
const int G = 5;
const int A = 6;
const int in_C = 2;
const int in_D = 3;
const int in_E = 4;
const int in_G = 5;
const int in_A = 6;

const int led_C = 9;
const int led_D = 10;
const int led_E = 11;
const int led_G = 12;
const int led_A = 13;

int switch_C, switch_D, switch_E, switch_G, switch_A = 0;

int smash = 0;

void setup() {
  // put your setup code here, to run once:
  pinMode(in_C, INPUT);
  pinMode(in_D, INPUT);
  pinMode(in_E, INPUT);
  pinMode(in_G, INPUT);
  pinMode(in_A, INPUT);

  Serial.begin(9600);
  Serial.println("0");
}

void loop() {
  // put your main code here, to run repeatedly:
  switch_C = digitalRead(in_C);
  switch_D = digitalRead(in_D);
  switch_E = digitalRead(in_E);
  switch_G = digitalRead(in_G);
  switch_A = digitalRead(in_A);

  while (Serial.available()) {
    smash = 0;
    if (Serial.read() == '\n') {
      //Note C
      if (switch_C == 1) {                //released, if the two aluminum foils touch
        smash = C;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note D
      if (switch_D == 1) {                //released, if the two aluminum foils touch
        smash = D;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note E
      if (switch_E == 1) {                //released, if the two aluminum foils touch
        smash = E;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note G
      if (switch_G == 1) {                //released, if the two aluminum foils touch
        smash = G;
      }
      else if (switch_C && switch_D && switch_E && switch_G && switch_A == 0)
      { //released, if the two aluminum foils partLED
        smash = 0;
      }
      //Note A
      if (switch_A == 1) {                //released, if the two aluminum foils touch
        smash = A;
      }
      Serial.println(smash);
    }
  }
} 

CHALLENGES:

After receiving feedback from classmates, I have made several improvements:

  1. Adding visual cues with the demo melody
  2. Informing players how many notes they have recreated correctly

At the beginning of the showcase, someone flagged out a few bugs in the interface but nothing major. They were removed swiftly and the rest of the show went by smoothly in back-to-back user testing!

last note

Thank you so much for the semester. Happy Christmas holidays and have a joyful New Year. Have a restful winter break as well.

Warms regards,

Chi-Ting

Final project Digital Doodle: Ingy el sheikh& Fatema Nassar

Finally!!

This was quite a journey, with many ups and downs but definitely one that ended in relief and content! The idea of our final project revolved giving our audience a chance to go back to their childhood and just have fun! Anyone that interacts with our project is given the opportunity to just draw whatever their heart desires, and the physical interactivity (because users will draw with their hands)  gives it an extra interesting and more immersive experience. We wanted our project to give the user complete freedom, so they users can choose between 5 different brushes and use the color they want to draw using the color selector.

Implementation:

There were mainly two aspects of this project, the processing aspect and the Arduino aspect (and serial communication). This is essentially also how we split the work between us. Fatema essentially took on the challenge of the processing side of things and I took on the challenge of the Arduino side of things and the blog documentations. So Fatema is the one that created the beautiful generative art pieces that played the role of our brushes, and she worked on the fiducial tracking as well (which was a pain! so she did a great job). While I focused on the arduino side of things, wiring up the buttons and slide potentiometer, creating the color gradient and its code on processing, and creating the serial communication between arduino and processing, I also took responsibility of the blog documentation. However, we also found ourselves working together most of the time, Fatema would help me with the arduino when I was stuck and vice versa. So it eventually turned into us working together on most of the aspects of the project rather than individually which worked out great!

lessons learned/how to improve:

This project is one that definitely helped us grow. Naturally it was not a perfect linear growth, hence there is always room for improvement. reflecting on where we can improve is definitely an essential thing to do. After the showcase these are the things we noticed could have been executed better:

  1. During our presentation to the class on the 13th, a very inconvenient and stupid mistake (we just need to move the location of the project slightly due to lighting issue) caused us to panic and not be able to show the class our project. lesson learned! we should have set up earlier especially since our project was not very straight forward and is prone to spontaneous errors.Luckily it all worked out in the end.
  2. When it comes to the project itself, we found that we should have included some sort of feedback for when the buttons are pressed, just to let the person know which brush they are using.
  3. We also learned that sometimes the finer details take even more time and effort than the bigger aspects of the project! and they bring the project together at the end.

IM showcase:

Here are some of the very unique masterpieces that people created on our digital doodle in the showcase. It was so much fun seeing how different people interacted differently with our project!

And here are a few video out of many of people interacting with our project (you can see how people move in the camera on the screen)!!

Arduino code:

int left = 0;
int right = 0;
int buttonOne = 9;
int buttonTwo = 10;
int buttonThree = 11;
int buttonFour = 12;
int buttonFive = 13;
int buttonSix = 3;//reset
int buttonSeven = 5;//Draw
int buttonEight = 4;//saveScreen


int val1 = 0;
int val2 = 0;
int val3 = 0;
int val4 = 0;
int val5 = 0;
int val6 = 0;
int val7 = 0;
int val8 = 0;

void setup() {
  pinMode(buttonOne, INPUT);
  pinMode(buttonTwo, INPUT);
  pinMode(buttonThree, INPUT);
  pinMode(buttonFour, INPUT);
  //   pinMode(buttonFive, INPUT);
  Serial.begin(9600);
  Serial.println("0,0");

}
void loop() {
  while (Serial.available()) {
    right = Serial.parseInt();
    left = Serial.parseInt();
    if (Serial.read() == '\n') {

      int sensor = analogRead(A0);
      delay(1);
      val1 = digitalRead(buttonOne);
      delay(1);

      val2 = digitalRead(buttonTwo);
      delay(1);

      val3 = digitalRead(buttonThree);
      delay(1);
      //
      val4 = digitalRead(buttonFour);
      delay(1);

      val5 = digitalRead(buttonFive);
      delay(1);

      val6 = digitalRead(buttonSix);
      delay(1);

      val7 = digitalRead(buttonSeven);
      delay(1);
      
      val8 = digitalRead(buttonEight);
      delay(1);
  


      Serial.print(sensor);
      Serial.print(',');
      Serial.print(val1);
      Serial.print(',');
      Serial.print(val2);
      Serial.print(',');
      Serial.print(val3);
      Serial.print(',');
      Serial.print(val4);
      Serial.print(',');
      Serial.print(val5);
      Serial.print(',');
      Serial.print(val6);//
      Serial.print(',');
      Serial.print(val7);//
      Serial.print(',');
      Serial.println(val8);
    }
  }



}

Processing Code:

import processing.video.*;
import jp.nyatla.nyar4psg.*;
import processing.serial.*;
import java.util.*;
import processing.sound.*;

SoundFile beep;

int n=1, mode=1;
PVector mouseloc = new PVector(0, 0);
PVector p;

PImage img;
PGraphics pg;
Capture cam;
MultiMarker nya;

PImage save;

Brush myBrush = new Brush(1, 2, mouseloc);


// serial stuff
Serial myPort;
int xPos=0;
int yPos;
boolean onOff=false;
boolean onOff2=false;
PImage myImage;
color pix;

int [] val = {0, 0, 0, 0, 0, 0, 0, 0};
int [] valprev = {0, 0, 0, 0, 0, 0, 0, 0};

void setup() {
  //size(1280, 720, P3D);
  colorMode(RGB, 100);
  fullScreen(P3D);

  printArray(Serial.list());
  String portname=Serial.list()[2];
  println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  myImage  = loadImage("color.jpeg");

  //img = createImage(1920, 1080);
  //printArray(Capture.list());
  //cam=new Capture(this, 1920, 1080);
  pg = createGraphics(1440, 900, P3D);
  cam = new Capture(this, 640, 360);
  // String[] devices = Capture.list();
  //println(devices);
  print(cam.width +"  "+cam.height);
  cam.start();
  pg.beginDraw();
  pg.background(0);
  pg.loadPixels();
  pg.endDraw();


  nya=new MultiMarker(this, width, height, "data/camera_para.dat", NyAR4PsgConfig.CONFIG_PSG);
  nya.addARMarker("data/patt.hiro", 40);//id=0
  cam.start();

  background(0);
  loadPixels();
  //beep= new SoundFile(this,"Buzzer-sound.mp3");
  beep= new SoundFile(this,"beep-09.wav");
   
}

int c=0;

void draw() {

  c++;
  if (cam.available() !=true) {
    return;
  }

  background(255);
  if (cam.available() == true) {
    cam.read();
  }

  pg.beginDraw();
  //pg.background(0);
  pg.loadPixels();
  pg.translate(width, 0);
  pg.scale(-1, 1);
  pg.image(cam, 0, 0, width, height);
  pg.endDraw();

  nya.detect(pg);
  imageMode(CORNER);
  //nya.drawBackground(pg);
  updatePixels();
  image(pg,0,height-height/3,width/4,height/4);
  




  if ((!nya.isExist(0))) {
    return;
  }
  p=nya.screen2ObjectCoordSystem(0, width/2, height/2);
  image(pg,0,height-height/3,width/4,height/4);
  updatePixels();

  if (mode==1) {
    drawScreen();
  }
  // nya.endTransform();

  else if (mode==2) {
    loadPixels();
    save("pic"+String.valueOf(n++)+".jpeg");
    delay(10);
    loadPixels();
    takeScreenShot();
    mode=1;
    delay(500);
    mode=3;
  }
  else if(mode==3){
    //display
    pg.beginDraw();
    pg.background(200);
    pg.imageMode(CENTER);
    for(int i=1; i<n+1; i++){
      save = loadImage("pic"+i+".jpeg");
      pushMatrix();
      rotate(random(0,HALF_PI));
      float widthh=random(width/6,width/4), heightt=random(height/6,height/4),locX=random(width),locY=random(height);
      pg.image(save,locX, locY);
      popMatrix();
    }
  }
}


void drawScreen() {
  //brush color picker
  imageMode(CENTER);
  fill(0);
  rectMode(CENTER);
  noStroke();
  rect(myImage.width/2, myImage.height/2, myImage.width, myImage.height*1.5);
  image(myImage, myImage.width/2, myImage.height/2, myImage.width, myImage.height);
  color pix = get(xPos, myImage.height/2);
  fill(pix);
  stroke(0);
  rect(xPos, myImage.height/2, 10, myImage.height*1.5);

  buttonPressed();

  myBrush.setCol(pix);

  mouseloc.x = p.x;
  mouseloc.y = p.x;
  myBrush.draww(mouseloc);
  loadPixels();
}

//void sound(){
//  if (valprev[0] == 1) {
//   beep.play();
//  }
////  } else if (valprev[1] == 1 ) {
////    buzzer.play();
////  } else if (valprev[2]==1 ) {
////    beep.play();
////  } else if (valprev[3]==1 ) {
////     beep.play();
////  } else if (valprev[4]==1 ) {
////   beep.play();
////  }
////  // reset
////  else if (valprev[5]==1 ) {
////beep.play();
////    }
////  else if (valprev[6]==1 ) { //draw
////beep.play();
////  } else if (valprev[7]==1 ) { //save screen
////   beep.play();
////  }
////}
    
  

//  }


void buttonPressed() {
  if (val[0] == 1 ) {
    myBrush.setbrush(1);
   
  } else if (val[1] == 1 ) {
    myBrush.setbrush(2);
  } else if (val[2]==1 ) {
    myBrush.setbrush(3);
  } else if (val[3]==1 ) {
    myBrush.setbrush(4);
  } else if (val[4]==1 ) {
    myBrush.setbrush(5);
  }
  // reset
  else if (val[5]==1 ) {
    println("bla");
    background(0);
    loadPixels();
    //for (int i=0; i<width*height; i++) {
    //  pixels[i]=color(0);
    //}
  } else if (val[6]==1 ) { //draw
    mode=1;
  } else if (val[7]==1 ) { //save screen
    mode=2;
  }
}



void takeScreenShot(){
  rectMode(CENTER);
  stroke(50);
  rect(width/2, height/2, width,height);
  delay(100);
  
}

void serialEvent(Serial myPort) {
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null) {
    println(s);
    int values[]=int(split(s, ','));
    if (values.length==9) {
      xPos=(int)map(values[0], 89, 912, 0, myImage.width);

      //yPos=(int)map(values[1],0,1023,0, height);
      //yPos=height/2-230;
      //myBrush.setbrush(2);

      val[0] = (int)values[1];  // read it and store it in val[]
      val[1] = (int)values[2];
      val[2] = (int)values[3];
      val[3] = (int)values[4];
      val[4] = (int)values[5];
      val[5] = (int)values[6];//reset
      val[6] = (int)values[7];//draw
      val[7] = (int)values[8];//saveScreen
    }
    myPort.write(int(onOff)+","+int(onOff2)+"\n");
  }
  for(int i=0;i<8;i++){
    valprev[i]=val[i];
  }
}
class Brush {

  int brushN;

  float stepSize, linelength, diam;
  float angle;
  float x, y, tempX, tempY;
  color col;
  //
  int counter;
  PFont font;
  float fontSize;
  String letters;
  float  fontSizeMin;
  //

  //linemoduelw
  PShape lineModule;

  float [] numX={ -100, -70, 0, 70, 100, 70, 0, -70};
  float [] numY={ 0, 70, 100, 70, 0, -70, -100, -70};

  Brush(int defaultt, float step_size, PVector mouse) {
    // 1 blur
    // 2 random cylinder
    // 3 dynamic shapes
    // 4 text lines
    // 5 rotating lines
    brushN = defaultt;
    stepSize = step_size;
    angle = 270;
    x = mouseX;
    y = mouse.y;
    col = color(255);
    linelength = 100;
    diam = 2;
    fontSizeMin=200;

    fontSize=50;
    letters = "It isn't true that my mattress is made of cotton candy. It was the first time he had ever seen someone cook dinner on an elephant. Homesickness became contagious in the young campers' cabin. Every manager should be able to recite at least ten nursery rhymes backward.";
  }
  void setbrush(int brushn) {
    brushN=brushn;
  }
  void setSize(float size) {
    stepSize=size;
  }
  void setCol(int colorr) {
    col=colorr;
  }
  void setLineLength(float len) {
    linelength=len;
  }
  void setDiam(float diamm) {
    diam= diamm;
  }

  void setAngle(float ang) {
    angle=ang;
  }

  void draww(PVector mouse) {

    switch (brushN) {
    case 2:
      setLineLength(100);
      setSize(5);
      setDiam(2);
      blur(mouse);
      break;

    case 3:
      setLineLength(100);
      setSize(3);
      randomprisms(mouse);
      break;

    case 4:

      dynamicShapes(mouse);
      break;

    case 5:
      textlines(mouse);
      break;

    default :
      setLineLength(100);
      strokeWeight(1);
      rotatingLines(mouse);
      break;
    }
  }

  void helper_randomPrisms() {
    float angle = TWO_PI/8;
    float rad = 100 * random(0.5, 1);
    for (int i=0; i<8; i++) {
      numX[i]=cos(angle * i) * rad;
      numY[i]=sin(angle * i) * rad;
    }
  }

  void blur(PVector mouse) {
    float [] blurX ={ -stepSize, -stepSize, 0, stepSize, stepSize, stepSize, 0, -stepSize};
    float [] blurY ={         0, stepSize, stepSize, stepSize, 0, -stepSize, -stepSize, -stepSize};
    float d = dist(x, y, mouse.x, mouse.y);

    if (d > stepSize) {
      // gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
      angle = (float)Math.atan2(mouse.y-y, mouse.x-x);

      tempX = x;
      tempY = y;

      nya.beginTransform(0);
      //
      //translate(x, y);
      rotate(angle);
      noStroke();
      fill(col, 40);

      //
      for (int i=0; i<500; i++) {
        int dir =  int(random(0, 7));
        rotate(random(5));
        println(blurX[dir]);
        tempX=blurX[dir]*random(1, 10);
        tempY=blurY[dir]*random(1, 10);
        circle(tempX, tempY, diam);
      }
      //
      nya.endTransform();

      x = mouse.x;
      y = mouse.y;
    }
  }

  void randomprisms(PVector mouse) {
    float d = dist(x, y, mouse.x, mouse.y);

    if (d>stepSize) {
      // gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
      angle = (float)Math.atan2(mouse.y-y, mouse.x-x);
      for ( int i=0; i<8; i++) {
        numX[i]+=random(0-stepSize/2, stepSize/2);
        numY[i]+=random(0-stepSize/2, stepSize/2);
      }

      nya.beginTransform(0);
      //
      //translate(x, y);
      rotate(angle+random(-0.1, 0.1));
      stroke(col);
      strokeWeight(stepSize/4);
      rectMode(CENTER);
      noFill();
      rect(0, 0, linelength*random(0.95, 1)*d/100, linelength*random(0.95, 1)*d/100);

      nya.endTransform();

      x=x+(float)Math.cos((angle))*stepSize;
      y=y+(float)Math.sin((angle))*stepSize;
    }


    helper_randomPrisms();
  }

  void dynamicShapes(PVector mouse) {
    float d = dist(x, y, mouse.x, mouse.y);
    println("x: ", x, "y", y, " mouse.x: ", mouse.x, "mouse.y: ", mouse.y);
    if (d>stepSize) {
      //
      lineModule = createShape();
      stroke(col);
      strokeWeight(1);
      noFill();
      lineModule.beginShape();

      lineModule.vertex(100, 0); // first point

      lineModule.vertex(0, 100);// /
      lineModule.vertex(-100, 0);// \
      lineModule.vertex(0, -100);// /
      lineModule.vertex(100, 0);// \

      lineModule.endShape();
      // gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
      angle = (float)Math.atan2(mouse.y-y, mouse.x-x);


      nya.beginTransform(0);
      //
      //translate(mouse.x, mouse.y);
      rotate((angle-PI));
      shape(lineModule, 0, 0, d, noise(1+frameCount*0.0001)*10);
      //
      nya.endTransform();


      x=x+(float)Math.cos((angle))*stepSize;
      y=y+(float)Math.sin((angle))*stepSize;
    }
  }

  void textlines(PVector mouse) {
    float d = dist(x, y, mouse.x, mouse.y);
    if (d>stepSize) {
      // gets the angle between the mouse and the location of the brush so that next point is drawn in the right intended location
      angle = (float)Math.atan2(mouse.y-y, mouse.x-x);
      for ( int i=0; i<8; i++) {
        numX[i]+=random(-4, 4);
        numY[i]+=random(-4, 4);
      }

      nya.beginTransform(0);
      //
      //translate(x, y);
      rotate(angle+random(-0.1, 0.1));
      stroke(col);
      strokeWeight(stepSize/4);
      noFill();
      beginShape();
      curveVertex(numX[0], numY[0]);///////////////
      curveVertex(numX[0], numY[0]);///////////////
      curveVertex(numX[1], numY[1]);//mid
      curveVertex(numX[2], numY[2]);///////////////
      curveVertex(numX[3], numY[3]);// mid
      curveVertex(numX[4], numY[4]);///////////////
      curveVertex(numX[5], numY[5]);//mid
      curveVertex(numX[6], numY[6]);///////////////
      curveVertex(numX[7], numY[7]);//mid
      curveVertex(numX[0], numY[0]);///////////////
      curveVertex(numX[0], numY[0]);///////////////


      endShape();

      nya.endTransform();

      x=x+(float)Math.cos((angle))*stepSize;
      y=y+(float)Math.sin((angle))*stepSize;
    }



  }

  void rotatingLines(PVector mouse) {

    nya.beginTransform(0);
    strokeWeight(1);
    stroke(col);

    rotate(radians(angle));
    line(0, 0, linelength, 0);
    //
    nya.endTransform();

    angle +=5;

    linelength= int(noise(50+0.01*frameCount)*300);
  }
}

 

Final Project: Horror Journal

It’s the final project! My project, named “Horror Journal”, is a personal diary simulator of sorts. This project is an interactive version of the novel “The Horla”. The diary has 39 entries in total, spanning from May to September.  Find out more about how it works below!

View post on imgur.com

Moving Through the Entries: 

Right in front of the user are two sheets of paper labeled “Previous Entry” and “Next Entry”. Below the hand icons printed on each paper is a Force Sensing Resistor (FSR) wired to the Arduino. Without user interaction, Arduino communicates a “0” to Processing. When the user pushes on the sheet, the FSR generates higher values. Once a specified threshold is passed, Arduino communicates a “1” to Processing. Processing then detects the “1” and switches to the next or previous diary entry depending on the user interaction.

Summoning the Demon: 

In the novel being played in the project, the character writing the diary entries is experiencing some sort of mysterious illness. By the end of the story, we learn that the character is being possessed by some sort of demon who he names “The Horla”. Since this is the biggest plot point in the story, I thought it would only make sense to incorporate it in the user interaction. For this interaction, I used a webcam, a Big Demon Glove (also known as a beanie), and a servo. In Processing, I read frames from the webcam and applied frame differencing on them to detect motion within the area captured by the webcam. This area is outlined by the big red sheet seen on the table. The servo I’m using is taped on the Big Demon Glove. On the servo, a small paper strip which reads “The Horla” is taped. When the user places the Big Demon Glove on the red sheet area, the camera detects the motion of servo, or the paper strip more accurately. This triggers a red strip on the screen to grow. Once the red strip reaches the bottom of the screen, the interaction is triggered: the screen turns red and the voice of the narrator turns deeper, imitating a stereotypical demonic voice. Pictures of this interaction can be seen below:

View post on imgur.com

View post on imgur.com

The Interface: 

Aside from the interactions, my project consists of the Processing screen, which displays the text of the diary entry being played, and audio readings of the current entry. The screen consists of yellow, red, and black colors. Originally, I wanted to create a more elaborate screen interface that simulates a personal room environment. I quickly realized that going with a simpler interface would make more sense with the interactions I planned. Additionally, the simpler interface looked generally cleaner and easier to follow. I was happy to hear that other people agreed with me.

Overall Thoughts: 

I’m glad I went with this project. I have received variety of reactions at the showcase ranging from “This is a very specific project” to “Wow! [the demonic voice] is creepy”. I noticed that a video game type project might have been more approachable in the showcase, but I still had many people come over to take a look at my project. One limitation might have been that no one would actually be able to sit through the entire story being narrated in my project since it is so lengthy. I did think about this possibility in my design phase. I thought about several solutions such as cutting down on the content of the story, but keeping everything in and allowing the user to navigate through the content on their own made more sense to me. I also wish I had booked a speaker early on. When I tested my project in the lobby, it sounded fine, but I did not anticipate how loud it would actually be during the showcase. Either way, I was able to present my project to everyone who came by, so I’m glad it worked out.

Credits: 

Audio Reading:

Text:

http://www.eastoftheweb.com/short-stories/UBooks/Horl.shtml

Processing Code: 

import processing.sound.*;
import processing.video.*;
import processing.serial.*;

Serial myPort;
int prev_left=0;
int prev_right=1;
int left=0;
int right=0;
boolean onOff=false;
boolean onOff2=false;

Capture video;
int vidX, vidY;
PImage prevFrame;
float motion_threshold=20;

SoundFile s_bg, s_clock, s_breathing, s_drinkwater;
SoundFile[] entries_audio;
PImage paper;
PFont font;
String[] entries;
int entries_cnt = 39;
int paper_offset_y = 0;
int page_start_i = 0;

int letter_i = 0;

int red_level = 0;

int vid_width = 640;
int vid_height = 480;

color bg_yellow = color(229, 229, 144);
color bg_red = color(183, 0, 0);
color bg_color = bg_yellow;
color text_color = color(0);
color bar_color = bg_red;
float bg_phase = 0;
float bar_phase = 0;
float text_phase = 0;
float audio_phase = 0.8;

int entry_switch_offset = 0;
int entry_switch_threshold = 10;

int prev_entry = 0;
int curr_entry = 0;

int text_speed = 2;

float avgX = 0;
float avgY = 0;

String may = "8, 12, 16, 18, 25";
String june = "2, 3";
String july = "2, 3, 4, 5, 6, 10,\n12, 14, 16, 19, 21, 30";
String august = "2, 4, 6, 7, 8, 9,\n10, 11, 12, 13, 14, 15,\n16, 17, 18, 19, 20, 21,\n22";
String september = "10";

void setup() {
  fullScreen();
  background(bg_color);

  printArray(Serial.list());
  String portname=Serial.list()[0];
  //println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');

  String[] cameras = Capture.list();
  video = new Capture(this, width, height, cameras[1]);
  video.start();
  prevFrame=createImage(width, height, RGB);

  paper = loadImage("paper.jpg");

  font = createFont("SyneMono-Regular.ttf", 25);
  textFont(font);

  entries_audio = new SoundFile[entries_cnt];
  for (int i=0; i<entries_cnt; i++) {
    entries_audio[i] = new SoundFile(this, "entries_audio/"+i+".mp3");
  }
  s_bg = new SoundFile(this, "sound/Ambience/night-crickets-ambience-on-rural-property.wav");
  s_clock = new SoundFile(this, "sound/Ambience/loopable-ticking-clock.wav");
  s_breathing = new SoundFile(this, "sound/Human/breath-male.wav");
  s_drinkwater = new SoundFile(this, "sound/Human/drink-sip-and-swallow.wav");
  s_bg.loop(1, 0.5);
  s_clock.loop(1, 0.1);

  entries = new String[entries_cnt];
  for (int i=0; i<entries_cnt; i++) {
    entries[i] = readFile("entries/"+i+".txt");
  }
}

void draw() {
  background(bg_color);
  entry_switch_offset++;
  textSpeed();
  drawPaper();
  entrySwitch();
  detectMotion();
  playEntry(entries_audio[prev_entry], entries_audio[curr_entry]);
  displayCalendar();
  prev_left = left;
  prev_right = right;
}

void serialEvent(Serial myPort) {
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null) {
    int values[]=int(split(s, ','));
    if (values.length==2) {
      left=(int)values[0];
      right=(int)values[1];
    }
  }
  myPort.write(int(onOff)+","+int(onOff2)+"\n");
}


void drawPaper() {
  imageMode(CENTER);
  writeText(entries[curr_entry]);
}

void writeText(String text) {
  int x = (width/2) - (paper.width/6) + 70;
  int y = (height/2) - (paper.height/6) + 70;
  int char_width = 0;
  int char_row = 0;
  String date = "";
  int c = 0;
  while (text.charAt(c) != '.') {
    date = date + text.charAt(c);
    c++;
  }
  if (page_start_i == 0) {
    page_start_i = c+2;
  }

  pushMatrix();
  textSize(40);
  text(date, x, 80);
  popMatrix();

  pushMatrix();
  textSize(25);
  translate(x, y + paper_offset_y);
  fill(text_color);

  if (entry_switch_offset > entry_switch_threshold) {
    if (frameCount%text_speed == 0 && letter_i < text.length() && text.charAt(letter_i) != ' ') {
      letter_i++;
    } else if (letter_i < text.length() && text.charAt(letter_i) == ' ') {
      letter_i++;
    }
    for (int i=page_start_i; i < letter_i; i++) {
      char_width += textWidth(text.charAt(i));
      text(text.charAt(i), char_width, char_row*30);


      if (x + char_width >= (width/2) + (paper.width/6) - 160 && text.charAt(i) == ' ') {
        char_row++;
        char_width = 0;
      }
      if (text.charAt(i) == '\n') {
        char_row++;
        char_width = 0;
      }
    }

    if (char_row > 19) {
      page_start_i = letter_i;
    }
  }
  popMatrix();
}

String readFile(String path) {
  String s = "";
  String[] arr = loadStrings(path);
  for (int i=0; i<arr.length; i++) {
    s = s + '\n' + arr[i];
  }
  return s;
}

void detectMotion() {
  if (video.available()) {
    prevFrame.copy(video, 0, 0, width, height, 0, 0, width, height);
    prevFrame.updatePixels();
    video.read();
  }
  video.loadPixels();
  prevFrame.loadPixels();
  loadPixels();
  float totalMotion=0;
  for (int y=0; y<height; y++) {
    for (int x=0; x<width; x++) {
      int loc = (video.width-x-1)+(y*width);
      color pix=video.pixels[loc];
      color prevPix=prevFrame.pixels[loc];
      float r1=red(pix);
      float g1=green(pix);
      float b1=blue(pix);
      float r2=red(prevPix);
      float g2=green(prevPix);
      float b2=blue(prevPix);
      float diff=dist(r1, g1, b1, r2, g2, b2);
      totalMotion+=diff;
      if (diff>motion_threshold) {
        avgX += x;
        avgY += y;
      }
    }
  }
  float avgMotion=totalMotion/pixels.length;
  avgX = avgX/pixels.length;
  avgY = avgY/pixels.length;
  fill(0);
  text(avgX + ' ' + avgY, 200, 800);
  if (avgMotion>motion_threshold && frameCount%1 == 0 && red_level <= height+10) {
    red_level += 10;
  } else if (frameCount%2 == 0 && red_level >= -5) {
    red_level -= 3;
  }
  video.updatePixels();
  prevFrame.updatePixels();
  updatePixels();
  if (avgMotion>motion_threshold) {
    fill(0);
    ellipse(width/2, 100, 30, 30);
  }
  pushMatrix();
  barSwitch();
  fill(bar_color);
  noStroke();
  rect(400, 0, 15, red_level);
  popMatrix();
  bgSwitch();
}

void bgSwitch() {
  if (red_level >= height) {
    bg_color = bg_red;
    bg_phase = 0;
    text_color = color(255);
  } else if (bg_color != bg_yellow && bg_phase<1) {
    bg_phase = phaseFade(bg_phase);
    text_phase = phaseFade(text_phase);
    bg_color = colorFade(bg_color, bg_red, bg_yellow, bg_phase);
    text_color = colorFade(text_color, color(255), color(0), text_phase);
  } else {
    bg_color = bg_yellow;
    text_color = color(0);
    bg_phase = 0;
    text_phase = 0;
  }
}

void barSwitch() {
  if (red_level >= height) {
    bar_color = bg_yellow;
    bar_phase = 0;
  } else if (bar_color != bg_red && bar_phase<1) {
    bar_color = colorFade(bar_color, bg_yellow, bg_red, bar_phase);
    bar_phase = phaseFade(bar_phase);
  } else {
    bar_color = bg_red;
    bar_phase = 0;
  }
}

color colorFade(color curr, color from, color to, float phase) {
  if (frameCount%10 == 0) {
    return lerpColor(from, to, phase);
  }
  return curr;
}

float phaseFade(float phase) {
  if (frameCount%10 == 0) {
    return phase + 0.01;
  }
  return phase;
}

void playEntry(SoundFile preventry, SoundFile currentry) {
  audioSpeed();
  if (!currentry.isPlaying()) {
    if (preventry.isPlaying()) {
      preventry.stop();
    }
    currentry.play();
  }
}

void audioSpeed() {
  if (red_level >= height && bg_color == bg_red) {
    audio_phase = 0.8;
  } else if ( bg_color != bg_yellow && frameCount%10 == 0) {
    audio_phase += 0.002;
  } else if (bg_color == bg_yellow) {
    audio_phase = 1;
  }
  entries_audio[curr_entry].rate(audio_phase);
}

void entrySwitch() {
  if (left == 1 & prev_left == 0  && curr_entry > 0) {
    prev_entry = curr_entry;
    curr_entry--;
    page_start_i = 0;
    letter_i = 0;
  }
  if (right == 1 && prev_right == 0  && curr_entry < entries_cnt-1) {
    prev_entry = curr_entry;
    curr_entry++;
    page_start_i = 0;
    letter_i = 0;
  }
}

void textSpeed() {
  if (red_level >= height) {
    text_speed = 4;
  } else {
    text_speed = 3;
  }
}

void displayCalendar() {
  int offset = 40;
  text("May", 50, 150);
  text("June", 50, 250);
  text("July", 50, 350);
  text("August", 50, 500);
  text("September", 50, 720);
  fill(text_color);
  text(may, 50, 150+offset);
  text(june, 50, 250+offset);
  text(july, 50, 350+offset);
  text(august, 50, 500+offset);
  text(september, 50, 720+offset);
  
  fill(bar_color);
}

Arduino Code:

#include <Servo.h>

#define right_fsr_pin A1
#define left_fsr_pin A0
#define threshold 900

int right_fsr_val;
int left_fsr_val;

int left = 0;
int right = 0;

Servo myServo;
const int servoPin = 3;

long currmillis = 0;
int angle = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("0,0");
  myServo.attach(servoPin);
}

void loop() {
  while (Serial.available()) {
    right = Serial.parseInt();
    left = Serial.parseInt();
    if (Serial.read() == '\n') {
      left_fsr_val = analogRead(left_fsr_pin);
      delay(1);
      right_fsr_val = analogRead(right_fsr_pin);
      delay(1);

      if (left_fsr_val >= threshold) {
        left_fsr_val = 1;
      } else {
        left_fsr_val = 0;
      }
      if (right_fsr_val >= threshold) {
        right_fsr_val = 1;
      } else {
        right_fsr_val = 0;
      }

      Serial.print(left_fsr_val);
      Serial.print(',');
      Serial.println(right_fsr_val);
    }
  }

    if (currmillis + 1000 <= millis()) {
      if (angle <= 10) {
        angle = 180;
      } else {
        angle = 0;
      }
      myServo.write(angle);
      currmillis = millis();
    }
}

 

Final Project Documentation: Leo Shirky

Project Idea:

I wanted to use the instrument that Gopika and I made for one of the earlier assignments in a creative way. Given that I had an instrument that people could play, I decided to make a project where people could choose a song that they wanted to hear, and then play that song on the instrument.

I had originally planned to have the only sound come from the Piezo buzzer, however the Professor told me about a program called Sforzando, which is a software which allows the sound of musical instruments to be played from a computer. I coded four songs that I wanted to be played from the computer in Processing, and connected that to Sforzando, allowing the songs to sound much better than if they had been played on the Piezo buzzer.

The serial communication happened between Processing and Arduino by lighting up LEDs depending on which note was being played in each song. These LEDs also lit up when a note was played on the instrument. The instrument itself used an Ultrasonic Distance Sensor, and had 10cm ranges that mapped on to a specific note, which would then be played from the Piezo buzzer.

Videos:

Reflections:

There were some aspects of the project that I wish I could have improved, but either didn’t have the time or the knowledge to.

The first is that I would have requested to use speakers, rather than my computer speakers. I hadn’t taken into account that the ambient noise of the show would drown out even the loudest volume on my computer, which had always been too loud in tests. The result was that it could be hard to pick out the melody that was being played from the computer.

I wanted to play instrument through Sforzando rather than the Piezo buzzer, as the buzzer doesn’t sound as good and was quieter than the computer speakers. Unfortunately, despite spending hours trying to figure it out, I just couldn’t get this type of serial communication to work in this direction. I had to settle for the buzzer in order to finish the rest of the project in time for the show.

The last major improvement would have been to have multiple octaves, rather than just one. Unfortunately this would have required more space and would have been inconvenient to play, so I settled on just the one octave. I also couldn’t add flat or sharp notes, as I had a limited amount of space and decreasing the distance that counts as a note below about 10 cm makes the instrument much harder to play.

Code:

Arduino:

#define echoPinC 12
#define trigPinC 11

#include "pitches.h"

String notes[7] = {"C4", "D4", "E4", "F4", "G4", "A4", "B4"};

int notesH[7] = {NOTE_C4, NOTE_D4, NOTE_E4, NOTE_F4, NOTE_G4, NOTE_A4, NOTE_B4};

long durationC;
int distanceC;

int bNote = 0;
int aNote = 0;
int gNote = 0;
int fNote = 0;
int eNote = 0;
int dNote = 0;
int cNote = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("0,0");
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);

//USDS code
  pinMode(trigPinC, OUTPUT);
  pinMode(echoPinC, INPUT);
}

void loop() {
//USDS Code
  digitalWrite(trigPinC, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPinC, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPinC, LOW);
  durationC = pulseIn(echoPinC, HIGH);
  distanceC = durationC * 0.034 / 2; 

  Serial.println("DistanceC: ");
  Serial.print(distanceC);
  Serial.print(" cm");
  Serial.print("mapped: ");

  int constrainedInput=constrain(distanceC, 1, 70);
  int mappedNote=map(constrainedInput, 1, 70, 0, 6);
  Serial.println(notes[mappedNote]);

  if(distanceC < 80){
    tone(10, notesH[mappedNote]);
  }else{
    noTone(10);
  }
    if(distanceC > 80){
    noTone(10);
  }
  if(mappedNote == 0){
    digitalWrite(2, HIGH);
  }else{
    digitalWrite(2, LOW);
  }
  if(mappedNote == 1){
    digitalWrite(3, HIGH);
  }else{
    digitalWrite(3, LOW);
  }
  if(mappedNote == 2){
    digitalWrite(4, HIGH);
  }else{
    digitalWrite(4, LOW);
  }
  if(mappedNote == 3){
    digitalWrite(5, HIGH);
  }else{
    digitalWrite(5, LOW);
  }
  if(mappedNote == 4){
    digitalWrite(6, HIGH);
  }else{
    digitalWrite(6, LOW);
  }
  if(mappedNote == 5){
    digitalWrite(7, HIGH);
  }else{
    digitalWrite(7, LOW);
  }
  if(mappedNote == 6){
    digitalWrite(8, HIGH);
  }else{
    digitalWrite(8, LOW);
  }
  if(distanceC > 80){
    digitalWrite(8, LOW);
  }

    while (Serial.available()) {
    bNote = Serial.parseInt();
    aNote = Serial.parseInt();
    gNote = Serial.parseInt();
    fNote = Serial.parseInt();
    eNote = Serial.parseInt();
    dNote = Serial.parseInt();
    cNote = Serial.parseInt();
    if (Serial.read() == '\n') {
      digitalWrite(8, bNote);
      digitalWrite(7, aNote);
      digitalWrite(6, gNote);
      digitalWrite(5, fNote);
      digitalWrite(4, eNote);
      digitalWrite(3, dNote);
      digitalWrite(2, cNote);
      
      
      Serial.print(mappedNote);
      Serial.print(',');
    }
  }
}

//NEW TAB

#define NOTE_B0  31
#define NOTE_C1  33
#define NOTE_CS1 35
#define NOTE_D1  37
#define NOTE_DS1 39
#define NOTE_E1  41
#define NOTE_F1  44
#define NOTE_FS1 46
#define NOTE_G1  49
#define NOTE_GS1 52
#define NOTE_A1  55
#define NOTE_AS1 58
#define NOTE_B1  62
#define NOTE_C2  65
#define NOTE_CS2 69
#define NOTE_D2  73
#define NOTE_DS2 78
#define NOTE_E2  82
#define NOTE_F2  87
#define NOTE_FS2 93
#define NOTE_G2  98
#define NOTE_GS2 104
#define NOTE_A2  110
#define NOTE_AS2 117
#define NOTE_B2  123
#define NOTE_C3  131
#define NOTE_CS3 139
#define NOTE_D3  147
#define NOTE_DS3 156
#define NOTE_E3  165
#define NOTE_F3  175
#define NOTE_FS3 185
#define NOTE_G3  196
#define NOTE_GS3 208
#define NOTE_A3  220
#define NOTE_AS3 233
#define NOTE_B3  247
#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951
#define NOTE_C8  4186
#define NOTE_CS8 4435
#define NOTE_D8  4699
#define NOTE_DS8 4978

Processing:

//this is for serial communication
import processing.serial.*;
Serial myPort;

  int channel = 0;
  int midiB4 = 71;
  int midiAB4 = 70;
  int midiA4 = 69;
  int midiGA4 = 68;
  int midiG4 = 67;
  int midiFG4 = 66;
  int midiF4 = 65;
  int midiE4 = 64;
  int midiDE4 = 63;
  int midiD4 = 62;
  int midiCD4 = 61;
  int midiC4 = 60;
  
  int velocity = 127;
  int timeInterval = 25; //keep at 25
  
  int wholeNote = 64*timeInterval;
  int halfNote = 32*timeInterval;
  int thirdNote = 24*timeInterval;
  int quarterNote = 16*timeInterval;
  int eighthNote = 8*timeInterval;
  int sixteenthNote = 4*timeInterval;
  int thirtysecondNote = 2*timeInterval;
  int sixtyfourthNote = 1*timeInterval;
  
  int freq=0;
  
  boolean bNoteOnOff=false;
  boolean aNoteOnOff=false;
  boolean gNoteOnOff=false;
  boolean fNoteOnOff=false;
  boolean eNoteOnOff=false;
  boolean dNoteOnOff=false;
  boolean cNoteOnOff=false;
  
  PImage beethoven;
  PImage happyBirthday;
  PImage littleApple;
  PImage uae;

//this is for MIDI
import themidibus.*; //Import the library

MidiBus myBus; // The MidiBus

void setup(){
  size(displayWidth, displayHeight);
  background(255);
  
  beethoven = loadImage("beethoven.png");
  happyBirthday = loadImage("happyBirthday.png");
  littleApple = loadImage("littleApple.png");
  uae = loadImage("uae.png");
  
  image(beethoven, 0, 0, displayWidth/2, displayHeight/2);
  image(happyBirthday, displayWidth/2, 0, displayWidth/2, displayHeight/2);
  image(littleApple, 0, displayHeight/2, displayWidth/2, displayHeight/2);
  image(uae, displayWidth/2, displayHeight/2, displayWidth/2, displayHeight/2);
  
  //this is for serial communication
  printArray(Serial.list());
  String portname=Serial.list()[4];
  println(portname);
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  
  textSize(40);
  fill(255);
  text("Press: 1", displayWidth/4, displayHeight/2 - 30);
  fill(0);
  text("Press: 2", displayWidth - displayWidth/4, displayHeight/2 - 30);
  text("Press: 3", displayWidth/4, displayHeight/2 + 20);
  text("Press: 4", displayWidth - displayWidth/4, displayHeight/2 + 20);
  
  MidiBus.list(); // List all available Midi devices on STDOUT. This will show each device's index and name.
  myBus = new MidiBus(this, -1, "sforzando"); // Create a new MidiBus with no input device and the default Java Sound Synthesizer as the output device.
}


void draw(){
  
  int value = 90;
  int channel = 0;
  
  myBus.sendControllerChange(channel, freq, value); // Send a controllerChange
  delay(2000);
  println("Frequency:" );
  print(freq);
}

void keyPressed(){
  switch(key){
    case'1': playOdeToJoy();
    break;
    case'2': playHappyBirthday();
    break;
    case'3': playXiaoPingGuo();
    break;
    case'4': playIshyBilady();
    break;
  }
}


void noteOn(int channel, int pitch, int velocity) {
  // Receive a noteOn
  println();
  println("Note On:");
  println("--------");
  println("Channel:"+channel);
  println("Pitch:"+pitch);
  println("Velocity:"+velocity);
}

void noteOff(int channel, int pitch, int velocity) {
  // Receive a noteOff
  println();
  println("Note Off:");
  println("--------");
  println("Channel:"+channel);
  println("Pitch:"+pitch);
  println("Velocity:"+velocity);
}

void controllerChange(int channel, int number, int value) {
  // Receive a controllerChange
  println();
  println("Controller Change:");
  println("--------");
  println("Channel:"+channel);
  println("Number:"+number);
  println("Value:"+value);
}

void delay(int time) {
  int current = millis();
  while (millis () < current+time) Thread.yield();
}

void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    println(s);
    int values[]=int(split(s,','));
    if (values.length==1){
      freq=(int)map(values[0],0,6,60,71);
    }
  }
  myPort.write(int(cNoteOnOff)+","+int(dNoteOnOff)+","+int(eNoteOnOff)+","+int(fNoteOnOff)+","+int(gNoteOnOff)+","+int(aNoteOnOff)+","+int(bNoteOnOff)+"\n");
}


//NEW TAB

void playHappyBirthday(){
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(halfNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(halfNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiA4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = true;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiA4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiB4, velocity); // Send a Midi noteOn
  bNoteOnOff = true;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiB4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiB4, velocity); // Send a Midi noteOn
  bNoteOnOff = true;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiB4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiA4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = true;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiA4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(halfNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  int number = 0;
  int value = 90;

  myBus.sendControllerChange(channel, number, value); // Send a controllerChange
  delay(2000);
}

//NEW TAB

void playIshyBilady(){
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiA4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = true;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiA4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiA4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = true;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiA4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(halfNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  int number = 0;
  int value = 90;

  myBus.sendControllerChange(channel, number, value); // Send a controllerChange
  delay(2000);
}


//NEW TAB

void playOdeToJoy(){

  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiE4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = true;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(thirdNote);
  myBus.sendNoteOff(channel, midiE4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(halfNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;

  int number = 0;
  int value = 90;

  myBus.sendControllerChange(channel, number, value); // Send a controllerChange
  delay(2000);
}


//NEW TAB

void playXiaoPingGuo(){
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiAB4, velocity); // Send a Midi noteOn
  bNoteOnOff = true;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiAB4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiAB4, velocity); // Send a Midi noteOn
  bNoteOnOff = true;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiAB4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiG4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = true;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiG4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  delay(eighthNote);
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiAB4, velocity); // Send a Midi noteOn
  bNoteOnOff = true;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiAB4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiC4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = true;
  delay(eighthNote);
  myBus.sendNoteOff(channel, midiC4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiF4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = true;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiF4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiD4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = true;
  cNoteOnOff = false;
  delay(quarterNote);
  myBus.sendNoteOff(channel, midiD4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiA4, velocity); // Send a Midi noteOn
  bNoteOnOff = false;
  aNoteOnOff = true;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(thirdNote);
  myBus.sendNoteOff(channel, midiA4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  myBus.sendNoteOn(channel, midiAB4, velocity); // Send a Midi noteOn
  bNoteOnOff = true;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  delay(halfNote);
  myBus.sendNoteOff(channel, midiAB4, velocity); // Send a Midi nodeOff
  bNoteOnOff = false;
  aNoteOnOff = false;
  gNoteOnOff = false;
  fNoteOnOff = false;
  eNoteOnOff = false;
  dNoteOnOff = false;
  cNoteOnOff = false;
  
  int number = 0;
  int value = 90;

  myBus.sendControllerChange(channel, number, value); // Send a controllerChange
  delay(2000);
  
}

 

Final Project : SPACE SURVIVAL 🚀💫

Description of the Assignment: 

Create a physically interactive system of your choice that relies on a multimedia computer for some sort of processing or data analysis. The Final should use BOTH Processing AND Arduino.Your focus should be on careful and timely sensing of the relevant actions of the person or people that you’re designing this for, and on clear, prompt, and effective responses. Any interactive system is going to involve systems of listening, thinking, and speaking from both parties. Whether it involves one cycle or many, the exchange should be engaging. You may work alone or in pairs.

Description of the Projects: 

This game is a typical 90s arcade space shooter game where you control a space ship and shoot bullets at the asteroid to protect yourself. In this version of the game, instead of using the basic key controls, the player uses the motions of the hand to control the space ship and shoot bullets at the asteroid.

Process: 

The  command for the motion of the ship is given via the ultrasonic sensor.The distance between the players hand and the ultrasonic sensor determines the x-coordinate  of the ship in the game. I used the   to detect the change in light when the player closes his/her fist to shoot bullets. I mapped the sensor reading from 0 to 1023, to 0 to 10. Then I divided the readings into 2. When the photoresistor read above or equal to 5, the bullets would shoot, and the red light would light up, otherwise the blue led would light up indicating that the value is below 5.

For the processing , I created stars and asteroid in a loop as a separate function by putting them in an Array with random values across the width of the screen. The values for the bullets too are kept in an Array, but their x coordinate starts from the x-coordinate of the ship +100 (center of the ship) and the same as y -coordinate of the ship . For the spaceship, I used the following picture, resized to 200 by 100.

 

Here is also a picture of the overall set up:

 

Video: 

 

Code: 

Arduino:

int left = 0;
int right = 0;
//int buzzer = 5;

const int echoPin = 2;  // attach pin D2 Arduino to pin Echo of HC-SR04
const int trigPin = 3; //attach pin D3 Arduino to pin Trig of HC-SR04

const int led_red = 9;
const int led_blue = 8;
const int photo = A0;


// defines variables
long duration; // variable for the duration of sound wave travel
int distance; // variable for the distance measurement

void setup() {
  Serial.begin(9600);
  Serial.println("0,0");
  //  pinMode(buzzer, OUTPUT);
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
  pinMode (led_red, OUTPUT);
  pinMode(led_blue, OUTPUT);
  pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT


}

void loop() {

  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  duration = pulseIn(echoPin, HIGH);

  // Calculating the distance
  distance = duration * 0.034 / 2; // Speed of sound wave divided by 2 (go and back)

  int constrained_distance = constrain(distance, 0, 30); //constraining distance to be detected
  int mapped_distance = map(constrained_distance, 0, 30, 0, 1300); // mapping the values as per convinience 

  int light = analogRead(photo); // reading values from photoresistor
  int mapped_light = map(light, 0, 1023, 0, 10); //mapping the values from photoresistor as per convinience 
  int constrained_light = constrain(light, 900, 1000);
  
  int value = 0;
  int numReadings = 10;

  for (int i = 0; i < numReadings; i++) {
    value = value + mapped_distance;
    delay(1);
  }

  int selected_value = value / numReadings; //taking avg of numbers in group of 10
  int avg_value = selected_value / 4; //taking average of the above number 

  //establishing communication between processing and arduino

  while (Serial.available()) {
    right = Serial.parseInt();
    left = Serial.parseInt();
    if (Serial.read() == '\n') {
        
      Serial.print(avg_value);
      Serial.print(",");
      Serial.println(mapped_light);
     
    }
  }

  //condition for led lights to switch on and off
  if (mapped_light <= 5) {
    digitalWrite(led_red, HIGH); // turn the LED on
    digitalWrite(led_blue, LOW);
  } else {
    digitalWrite(led_red, LOW); // otherwise turn it off
    digitalWrite(led_blue, HIGH);
  }
}
}

Processing: 

import processing.serial.*;
import processing.sound.*;

Serial myPort;
SoundFile shoot;
SoundFile crash;
PImage ship;

int xPos=width/2;
int yPos=0;
float Ship;

ArrayList<Star> stars = new ArrayList<Star>(); //array for stars
int frequency = 4; //frequency of star


ArrayList<Asteroid> asteroids = new ArrayList<Asteroid>(); //array for asteroid
int asteroidFrequency = 25; //frequency of ateroid

ArrayList<Bullet> bullets = new ArrayList<Bullet>(); //array for bullets

int points;
boolean instruct = true;

EndScene end;

void setup() {
  //establishing connection with Arduino
  String portname=Serial.list()[4];
  //println(portname);
  myPort = new Serial(this, portname, 9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  fullScreen();
  points = 0;
  ship = loadImage("spaceplane.png"); //loading image
  shoot = new SoundFile(this, "lazershoot_sound.wav");// shoot sound
  crash = new SoundFile(this, "space_crash.mp3");//crash sound
}

void draw() {

  if (end != null) {
    end.drawEndScene();
  } else {

    background(0);
    drawStar();

    serialEvent(myPort);
    fill(255);
    image(ship, xPos, height - height/4, 200, 100);
    drawBullet();
    if (instruct == true) {
      StartScene();
    } else {
      drawAsteroid();
      fill(255, 0, 0);
      stroke(255);



      stroke(255);
      fill(255);
      textSize(30);
      text("Points: " + points, 50, 50);

      checkCollision();
    }
  }
}


void drawBullet() {
  for (int i = 0; i<bullets.size(); i++) {
    bullets.get(i).drawBullet();
  }
}

void checkCollision() {
  for (int i = 0; i < asteroids.size(); i++) {
    Asteroid a = asteroids.get(i);
    float tan_shoot =  10*tan(60);
    float distance_ship= dist(a.x, a.y, xPos, (height-height/4)-tan_shoot);
    float distance_shipleft= dist(a.x, a.y, xPos+200, (height-height/4)+tan_shoot);
    if (distance_ship< a.size/2 +tan_shoot) {
      crash.play();
      end = new EndScene();
    }
    if (distance_shipleft<a.size/2+tan_shoot){
      crash.play();
      end = new EndScene();
    }
    for (int b = 0; b < bullets.size(); b++) {
      Bullet bullet = bullets.get(b);
      if (a.checkCollision(bullet) == true) {
        points++;

        asteroids.remove(a);
        bullets.remove(b);
      }
    }
  }
}


void drawAsteroid() {
  if (frameCount % asteroidFrequency == 0) {
    asteroids.add(new Asteroid(random(100, 250)));
  }
  for (int i = 0; i<asteroids.size(); i++) {
    Asteroid currentAsteroid = asteroids.get(i);
    currentAsteroid.drawAsteroid();
    if (currentAsteroid.y > height + currentAsteroid.size) {
      asteroids.remove(currentAsteroid);
      i--;
      points--;
    }
  }
}

void drawStar() {
  strokeWeight(1);
  stroke(255);
  if (frameCount % frequency == 0) {
    Star myStar = new Star();
    stars.add(myStar);
  }
  for (int i = 0; i<stars.size(); i++) {
    Star currentStar = stars.get(i);
    currentStar.drawStar();
  }
}

void serialEvent(Serial myPort) {
  loop();
  //frameRate(10);
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null) {
    println(s);
    int values[]=int(split(s, ','));
    if (values.length==2 ) {
      //if (values[0]>=0) {
      xPos=(int)map(values[0], 0, 325, 0, width);
      //println(values[0]);
      println(xPos);
      if (xPos < 0) {
        xPos = 0;
        //}
      }
      if (xPos > width) {
        xPos = width;
      }
    }

    if ( values[1] <= 5) {
      Bullet b = new Bullet();
      bullets.add(b);
      shoot.amp(0.4);
      //shoot.play();
    }
  }
  myPort.write("0"+"\n");
}


void mousePressed() {
  if (end != null && end.mouseOverButton() == true) {
    resetGame();
  }
}

void resetGame() {
  instruct= true; 
  stars.clear();
  bullets.clear();
  asteroids.clear();
  end = null;
  points = 0;
}

void StartScene() {
  strokeWeight(7);
  stroke(0);
  fill(255);
  textSize(30);
  textAlign(CENTER);
  text("Try to move you hand within the taped area on the table", width/2, height/2-100);
  text(" Try opening and closing your hand completely to shoot bullets", width/2, height/2);
  text("PRESS SHIFT TO PLAY", width/2, height/2+100);
  if (keyPressed) {
    if (keyCode == SHIFT) {
      instruct = false;
    }
  }
}


class Asteroid {
  float size;
  float x;
  float y;
  int num;

  int speed_asteroid = 10; //speed of asteroid

  Asteroid(float size) {
    this.size = size;
    this.x = random(width);
    this.y = 0;
  }

  void drawAsteroid() {
    fill(150);
    stroke(150);
    ellipse(x, y, size, size);
    y+=speed_asteroid;
  }

  boolean checkCollision( Object crash) {
    if (crash instanceof Bullet) {
      Bullet bullet = (Bullet) crash;
      float distance_bullet = dist(x, y, bullet.x, bullet.y);
      if (distance_bullet <= size + bullet.size/2 ) {
        //fill(0, 255, 0, 100);
        //rect(0, 0, width, height);
        fill(255);

        return true;
      }
    }
    return false;
  }
}


class Bullet {
  float x;
  float y;
  float velocity_y;
  float size;

  Bullet() {
    this.x = xPos;
    this.y = (height-height/4) - 15;
    this.velocity_y = -10;
    this.size = 10;
  }

  void drawBullet() {
    fill(255);
    ellipse(x+100, y, size, size);
    y +=velocity_y;
    
  }
}


class EndScene {
  int button_x;
  int button_y; 
  int button_width; 
  int button_height;


  EndScene() {
    this.button_width = 300;
    this.button_height = 100;
    this.button_x = width/2 - this.button_width/2;
    this.button_y = height/2 - this.button_height/2;
  }

  void drawEndScene() {
    //Background
    fill(#FAE714);
    rect(0, 0, width, height);
    rect(button_x, button_y, button_width, button_height);

    //Game over text
    stroke(0);
    fill(0);
    textSize(150);
    textAlign(CENTER);
    text("GAME OVER!", width/2, height/4);

    //Restart Button
    fill(0);
    stroke(200);
    rect(button_x, button_y, button_width, button_height);
    fill(200);
    textSize(60);
    textAlign(CENTER); 
    text("RETRY?", button_x+150, button_y+70);
    
    //Player Score 
    stroke(0);
    fill(0);
    textSize(80);
    textAlign(CENTER); 
    text("FINAL SCORE: " + points, width/2, height - height/4);
  }

  boolean mouseOverButton() {
    return (mouseX > button_x 
      && mouseX < button_x + button_width
      && mouseY > button_y
      && mouseY < button_y + button_height);
  }
}


class Star {
  float x;
  float y;
  int velocity_star;
  
  Star() { 
    this.x = random(width);
    this.y = 0;
    this.velocity_star = 10; //velocity of falling star
  }
  
  void drawStar() {
    y+=velocity_star;
    fill(#FCEB24);
    circle(x,y,5);
  }
}

 

(Final Project) Toy Grabber Machine – Jade

VIDEOS / IMAGES

__________________

 

 

PROCESS

__________________

How to play

First, the player should toss the coin into the coin pusher, which will start the game. Then the player uses the joystick to move the claw left or right, and the button to make the claw go down for the toys. I also added sound effects for different moves, so that it’s more interesting.

There is also a hidden prize which only three lucky persons today got it. Some people really wanted to get the prize and tried so hard at it — almost grabbed every toy.

 

Challenges

The coding part on Processing is quite challenging, and I spent quite some time on the física package so that I know how it works. One of the difficulties I encounter was the part where the claw goes down to grab, then drops it and finally returns.  It was such a headache to figure out how to make the claw know if it touches a toy or not. I solved this by setting another física object on the tip of the claw to detect physical collision. I also used many booleans to make this small animation.

The edge setting was also tricky. I have to make sure that the claw doesn’t go out of the screen or works weirdly. To avoid those rule-breaking people who wants to see what happens if the claw goes down in the drop box — I set it that the claw will just head back instead of going down. And if the claw doesn’t catch anything, as it touches the edge, it will automatically go back.

When it came to the Arduino part, the coding was much easier, and the physical setting wasn’t that complicated. The most hard part was the coin pusher, I had to glue the distance to the box really tight to make sure it measures the distance correctly.

But the joystick was really hard to control — the numbers it gave off were pretty random at first, but after I soldered it, I found the patterns of the numbers although it wasn’t really stable. Also, the cables and the distance sensor often fell off, and the port sometimes got disconnected.

Right before the IMA show, the port got disconnected and some wires fell off. Fortunately, during the entire show, everything worked perfectly and didn’t crash, which was amazing and surprising as well!

 

Conclusion

It was such an amazing journey of learning Processing and Arduino, and connecting them through serial communication to produce such a complex project. I could never expect to do something like this at the beginning of this semester.

I want to thank the professor for being supportive and giving great suggestions. Thank you for pointing out the problems with the machine  and helping me fix them before the show, so that they all worked great for the entire time. I feel sorry for not being able to let you play the perfect version 🙁

Thank you all for this fabulous course! Everyone’s projects are so creative and interesting! It was pleasant to work with everyone :))

 

CODE

__________________

Arduino:

int joyX = A0;
int joyY = A1;
int button = 4;
int button_state;
const int trigPin = 7;
const int echoPin = 6;
int duration = 0;
int dist = 0;
int prize=0;

int red = 10;
int yellow = 9;
int blue = 8;

int posX;
int posY;



void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("0,0,0,0");
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(button, OUTPUT);
  pinMode(trigPin , OUTPUT);
  pinMode(echoPin , INPUT);
  pinMode(red, OUTPUT);
  pinMode(yellow , OUTPUT);
  pinMode(blue , OUTPUT);
  pinMode(2,INPUT);
  digitalWrite(2,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
//  int posX = analogRead(joyX); 
//  int posY = analogRead(joyY); 
//  Serial.println(posY);
//  Serial.println(posX);
  
  digitalWrite(red,prize);
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(2);
  digitalWrite(trigPin, LOW); 
   
  duration = pulseIn(echoPin, HIGH);
  dist = duration/58.2;
//  Serial.println(dist);

  while (Serial.available()) {
    prize = Serial.parseInt();
    if (Serial.read() == '\n'){ 
       button_state = digitalRead(button);
       // move 0
       posX = analogRead(joyX); 
       posY = analogRead(joyY); 
       
       if (posX >= 550) {
          Serial.print(1);   
       } else {
          Serial.print(0);
       }
       Serial.print(",");
       
       // move 1
       if (posX <= 360) {
          Serial.print(1);   
       } else {
          Serial.print(0);
       }
       Serial.print(",");   
           
       // grab 2
       if (button_state == 0) {
          Serial.print(0);
       } else {
          Serial.print(1);
       }
       Serial.print(",");
       
       // coin pusher 3

       if ( dist <= 5 )
          {
            Serial.println(1);
          } else {
            Serial.println(0);       
          }
        digitalWrite(red,prize);
        digitalWrite(yellow,prize);
        digitalWrite(blue,prize);
      }

     } 

}

Processing:

import fisica.*;
import processing.serial.*;
import processing.sound.*;

Serial myPort;

PImage claw;
PImage[][] claws;
PImage bird;
PImage[][] birds;
PImage bg;

boolean start = false;
boolean grab = false;
boolean get = false;
boolean drop = false;
boolean ret = false;
boolean prize = false;
boolean coin = false;
boolean right = false;
boolean left = false;

float speed;
float posX=20, posY=10;
FCircle[] bodies;

ArrayList<FBody> touching = new ArrayList<FBody>();
FCircle tip;
FBody prev_touch;

FWorld world;
int toy_num = 30;

SoundFile grab_sound;
SoundFile drop_sound;
SoundFile prize_sound;
SoundFile start_sound;
 
void setup() {
  fullScreen();
  size(750,600);
  
  printArray(Serial.list());
  String portname=Serial.list()[1];
  println(portname);
  myPort = new Serial(this,portname,9600);
  myPort.clear();
  myPort.bufferUntil('\n');
  
  //
  bg = loadImage("bg.jpeg");
  bg.resize(displayWidth, displayHeight);
  //bg.resize(750, 600);
  
  translate((displayWidth-750)/2, (displayHeight-600)/2+100);
  
  generate_claw();
  Fisica.init(this);
  world = new FWorld();
  world.setEdges(0, 0, 750, 530, 255);
  generate_birds();
  
  tip = new FCircle(35);
  tip.setFill(0);
  tip.setStatic(true);
  tip.setDrawable(false);
  world.add(tip);
  
  grab_sound = new SoundFile(this, "pick_up.wav");
  drop_sound = new SoundFile(this, "drop.wav");
  prize_sound = new SoundFile(this, "prize.wav");
  start_sound = new SoundFile(this, "coin.wav");
}

void draw() {
  //println(mouseX,mouseY);
  background(bg);
  
  translate((displayWidth-750)/2, (displayHeight-600)/2+100);
  world.step();
  world.draw();
  
  // box
  fill(255, 200);
  noStroke();
  rect(603, 250, 200, 280);
  strokeWeight(3);
  stroke(0);
  line(603, 250, 605, 530);
  
  if (coin) {
    start_sound.play();
    coin = false;
  }
  
  if (start){
    initialize_claw();
  } else {
    fill(#A09B10);
    PFont f = createFont("Dialog-48", 40);
    textFont(f);
    text("SWIPE a coin to START", 145, -100);
    fill(#671235);
    text("SWIPE a coin to START", 140, -100);
  }
}

void initialize_claw() {
  if (posX >= 750 - 80) {
    posX = 750-80;
  }
  
  if (posX <= 20) {
    posX = 20;
  }
  
  
  if (!grab) {
    if (ret) {
      if (posX > 20) {
        image(claws[0][0], posX, 10);
        posX -=3;
        if (prize) {
          fill(#901758);
          text("CONGRATULATIONS!!!", 150, 100);
          text("You are so LUCKY to get an AWARD", 80, 100);
        }
      } else {
        ret = false;
        world.remove(prev_touch);
        prize = false;
      }
    } else {
      image(claws[0][0], posX, 10);
      if (right) {
        posX += speed;
      }
      
      if (left) {
        posX -= speed;
      }
    }
  } else {
    if (posX >= 550 && !get) {
      grab = false;
      get = false;
      ret = true;
    } else {
    
    claw_down();
    if (posY<0) {
      posY+=3;
    }
    if (!drop) {
      FBody toy = world.getBody(posX+60, posY+80);
      if (get && posY < 20) {
        image(claws[6][0], posX, posY);
        if (posX <= 598) {
          posX += 3;
          toy.setPosition(posX+60, posY+80);
        } else {
          drop = true;
          drop_sound.play();
          toy.setStatic(false);
          grab = false;
          get = false;
          drop = false;
          ret = true;
          
        // prize
        int ram = (int)random(100);
        if (ram <= 1) {
          prize = true;
          prize_sound.play();
        }
        
         }
        }
      }
    }
  }
    
}

void claw_down() {
  FBody touch;
  tip.setPosition(posX+40, posY+90);
  if (posY < 500 && posY > 0) {
    touching = tip.getTouching();
    if (get) {
      image(claws[6][0], posX, posY);
      posY -= 3;
      if (touching.size()>0) {
        touch = touching.get(0);
        prev_touch = touch;
 
        touch.setStatic(true);
        touch.setPosition(posX+60, posY+80);
      }
    } else{
      image(claws[7][0], posX, posY);
      if (touching.size()>0) {
        get = true;
        grab_sound.play();
      } else {
        posY += 3;
        if (posY >= 500) {
          grab = false;
          get = false;
          ret = true;
        }
      }
    }
  }
}



void generate_claw() {
  claw = loadImage("claw.png");
  claws = new PImage[8][5];
  int w = claw.width / 5; 
  int h = claw.height / 8; 

  for (int y=0; y < 8; y++) {
    for (int x=0; x< 5; x++) {
      claws[y][x] = claw.get(x*w, y*h, w, h);
      claws[y][x].resize(100,120);
    }
  }   
}

void generate_birds() { 
  bodies = new FCircle[30];
  
  bird = loadImage("bird.png");
  birds = new PImage[2][3];
  int w1 = bird.width / 3;
  int h1 = bird.height / 2;
  
  for (int y=0; y < 2; y++) {
    for (int x=0; x< 3; x++) {
      birds[y][x] = bird.get(x*w1, y*h1, w1, h1);
      birds[y][x].resize(85, 85);
    }
  }
  
  for (int i=0; i<toy_num; i++) {
    int radius = 50;
    FCircle b = new FCircle(radius);
    b.setPosition(random(100, 500), height/2);
    b.setStroke(0);
    b.setStrokeWeight(2);
    b.setDensity(radius / 10);
    int random_x = int(random(0,2));
    int random_y = int(random(0,3));
    b.attachImage(birds[random_x][random_y]);
    world.add(b);
    bodies[i] = b;
  }
  
  FBox edge = new FBox(10, 300);
  edge.setPosition(600, 400);
  edge.setStatic(true);
  world.add(edge);
}


void mousePressed() {
  // if button pressed, reset
  world.clear();
  grab = false;
  ret = false;
  get = false;
  drop = false;
  start = false;
  
  bg = loadImage("bg.jpeg");
  bg.resize(displayWidth, displayHeight);
  translate((displayWidth-750)/2, (displayHeight-600)/2+100);
  generate_claw();
  Fisica.init(this);
  world = new FWorld();
  world.setEdges(0, 0, 750, 530, 255);
  generate_birds();
  
  tip = new FCircle(35);
  tip.setFill(0);
  tip.setStatic(true);
  tip.setDrawable(false);
  world.add(tip);
  posX = 20;
  posY = 10;
  
  initialize_claw();
}



void serialEvent(Serial myPort){
  String s=myPort.readStringUntil('\n');
  s=trim(s);
  if (s!=null){
    println(s);
    int values[]=int(split(s,','));
    if (values.length>=1){
      if (values[3] == 1) {
        coin = true;
        start = true;
      }
      
      if (values[0] == 1 && start) {
        left = false;
        right = true;
      } else {
        right = false;      
      }
      
      if (values[1] == 1 && start) {
        right = false;
        left = true;
      } else {
        left = false;      
      }      
      
      if (values[2] == 1 && start) {
        grab = true;
      }
      
    }
  }
  myPort.write(int(prize)+"\n");
  
}

 

 

Final Documentation – HeartBeat/Pulse Sensor – Lie detection maybe?

Description

Create a physically interactive system of your choice that relies on a multimedia computer for some sort of processing or data analysis. The Final should use BOTH Processing AND Arduino. Your focus should be on careful and timely sensing of the relevant actions of the person or people that you’re designing this for, and on clear, prompt, and effective responses. Any interactive system is going to involve systems of listening, thinking, and speaking from both parties. Whether it involves one cycle or many, the exchange should be engaging. You may work alone or in pairs.

Project

I started this project by working with a pulse sensor without thinking about what I would end up with. I progressed by displaying a heartbeat on the screen by using the data I received. I also wanted to work with LEDs, I attached the LEDs with the breadboard. I used two LEDs that turn on and off according to the pulse rate. I also checked the timings between heartbeats by subtracting the last-current, the variable I have used is TBH(time between heartbeats). I also made the heart pump by increasing the stroke weight. You can also use “S” or “s” to save the heartbeat in the folder where the code is saved and later you can compare the heartbeat. To make the pulse rate monitor more interesting, I added some questions to the screen to see how the heartbeat changed with respect to the question, which can be used as a lie detection test. If someone wanted to reset their heartbeats, they can press ‘r’ to reset it, and the monitor displays no heartbeat until some other person uses the sensor. For this project, I used two sensors, out of which one had technical problems. So, I couldn’t use that. But, the idea was that I would compare two people’s heartbeats by asking them questions.

I took some shots during the exhibition of people testing out the monitor and playing the yes/no question game.

The LEDs were covered with a white box that looked like an artificial heart because it would beat every time your pulse was beating. The circuit looked like this:

Certain challenges:-

  1. It took me some time to figure out how the sensor worked because I have never worked with a pulse sensor before.
  2. it was hard to display the pulse wave first, then I found some resources to make me understand the concept.
  3. it was hard to add further things to the project to make it more useful.

The code is following:-

Arduino

#define USE_ARDUINO_INTERRUPTS true
#include <PulseSensorPlayground.h>


const int OUTPUT_TYPE = PROCESSING_VISUALIZER;

const int PULSE_SENSOR_COUNT = 2;


const int PULSE_INPUT0 = A0;
const int PULSE_BLINK0 = 13;    //led
const int PULSE_FADE0 = 5;

const int PULSE_INPUT1 = A1;
const int PULSE_BLINK1 = 12;
const int PULSE_FADE1 = 11;

const int THRESHOLD = 550;   // to avoid noise when idle


PulseSensorPlayground pulseSensor(PULSE_SENSOR_COUNT);

void setup() {

  Serial.begin(250000);

  pulseSensor.analogInput(PULSE_INPUT0, 0);
  pulseSensor.blinkOnPulse(PULSE_BLINK0, 0);
  pulseSensor.fadeOnPulse(PULSE_FADE0, 0);

  pulseSensor.analogInput(PULSE_INPUT1, 1);
  pulseSensor.blinkOnPulse(PULSE_BLINK1, 1);
  pulseSensor.fadeOnPulse(PULSE_FADE1, 1);

  pulseSensor.setSerial(Serial);
  pulseSensor.setOutputType(OUTPUT_TYPE);
  pulseSensor.setThreshold(THRESHOLD);


  if (!pulseSensor.begin()) {
   
    for (;;) {
      
      digitalWrite(PULSE_BLINK0, LOW);
      delay(50);
      digitalWrite(PULSE_BLINK0, HIGH);
      delay(50);
    }
  }
}

void loop() {


  delay(20);

 
  pulseSensor.outputSample();

  for (int i = 0; i < PULSE_SENSOR_COUNT; ++i) {
    if (pulseSensor.sawStartOfBeat(i)) {
      pulseSensor.outputBeat(i);
    }
  }
}

Processing

import processing.sound.*;
SoundFile file;
import processing.serial.*;
PFont font;

Serial port;
int numSensors = 2; //variable that holds number of sensors
//the varible given below holds certain information
int[] Sensor;      
int[] TBH;         
int[] BPM;        
int[][] RawPPG;      
int[][] ScaledPPG;  
int[][] ScaledBPM;      
float offset;    
color bgcolor = color(171,219,227);
int heart[];   //when timing the pulse

//determine the size 
int pulseWidth; 
int pulseHeight; 
int pulseX;
int pulseY[];
int bpmWidth; 
int bpmHeight; 
int bpmX;
int bpmY[];
int spacer = 10;
boolean beat[]; //boolean to check if heart beat detected

//find serial port
String serialPort;
String[] serialPorts = new String[Serial.list().length];
boolean serialPortFound = false;
Radio[] button = new Radio[Serial.list().length*2];
int numPorts = serialPorts.length;
boolean refreshPorts = false;
int duration = 1000;
int pressTime;

void setup() {
  fullScreen();
  frameRate(100);
  font = loadFont("Arial-BoldMT-24.vlw");
  file = new SoundFile(this, "heart.mp3");
  textFont(font);
  textAlign(CENTER);
  rectMode(CORNER);
  ellipseMode(CENTER);
  pulseWidth = width-520;
  pulseHeight = 1080/numSensors;
  pulseX = 10;
  pulseY = new int [numSensors];
  for(int i=0; i<numSensors; i++){
    pulseY[i] = 43 + (pulseHeight * i);
    if(i > 0) pulseY[i]+=spacer*i;
  }
  bpmWidth = 300;
  bpmHeight = pulseHeight;
  bpmX = pulseX + pulseWidth + 10;
  bpmY = new int [numSensors];
  for(int i=0; i<numSensors; i++){
    bpmY[i] = 43 + (bpmHeight * i);
    if(i > 0) bpmY[i]+=spacer*i;
  }
  heart = new int[numSensors];
  beat = new boolean[numSensors];
  // Data Variables Setup
  Sensor = new int[numSensors];      
  TBH = new int[numSensors];         
  BPM = new int[numSensors];         
  RawPPG = new int[numSensors][pulseWidth];          
  ScaledPPG = new int[numSensors][pulseWidth];       
  ScaledBPM = new int [numSensors][bpmWidth];           
  //setting lines to 0
  resetDataTraces();

 background(0);
 noStroke();
 drawDataWindows();
 drawHeart();

  
  fill(bgcolor);
  text("Select Your Serial Port",245,30);
  listAvailablePorts();
}

void draw() {
  
if(serialPortFound){
  // run only when port connected
  background(0);
  drawDataWindows();
  drawPulseWaveform();
  drawBpmWave();
  drawHeart();
  printDataToScreen();
  
  if(spacePressed){
    text("The following game involves Yes/No questions.\n Press 1 to view the first question.", 670, 500);
  }
  if(onePressed){
    text("Are you happy with your life?", 700, 500);
  }
  if(twoPressed){
    text("Have you ever truly been in love?", 700, 500);
  }
  if(threePressed){
    text("Do you think you're successful in life?", 700, 500);
  }
  if(fourPressed){
    text("Have you ever done something unforgivable?", 750, 500);
  }
  if(fivePressed){
    text("Would you save your mother over 17 other random people?", 700, 500);
  }
  if(sixPressed){
    text("Are you a good person?", 700, 500);
  }
  if(sevenPressed){
    text("If you died tomorrow, would you have regrets?", 750, 500);
  }

} else { 
  autoScanPorts(); //scan to find port
  

  if(refreshPorts){
    refreshPorts = false;
    drawDataWindows();
    drawHeart();
    listAvailablePorts();
  }

  for(int i=0; i<numPorts+1; i++){
    button[i].overRadio(mouseX,mouseY);
    button[i].displayRadio();
  }

}

}  


void drawDataWindows(){
  noStroke();
  fill(bgcolor);  
  for(int i=0; i<numSensors; i++){
    rect(pulseX, pulseY[i], pulseWidth, pulseHeight);
    rect(bpmX, bpmY[i], bpmWidth, bpmHeight);
  }
}

void drawPulseWaveform(){
  for (int i=0; i<numSensors; i++) {
    RawPPG[i][pulseWidth-1] = (1023 - Sensor[i]);  
    

    for (int j = 0; j < pulseWidth-1; j++) {      
      RawPPG[i][j] = RawPPG[i][j+1];                         
      float dummy = RawPPG[i][j] * 0.625/numSensors;       
      offset = float(pulseY[i]);                
      ScaledPPG[i][j] = int(dummy) + int(offset);   
    }
    stroke(250, 0, 0);                               
    noFill();
    beginShape();                                  
    for (int x = 1; x < pulseWidth-1; x++) {
      vertex(x+10, ScaledPPG[i][x]);                    
    }
    endShape();
  }

}

void drawBpmWave(){
//draw bpm wave

for (int i=0; i<numSensors; i++) {  
if (beat[i] == true) {  
    file.play();
  beat[i] = false;      

    for (int j=0; j<bpmWidth-1; j++) {
      ScaledBPM[i][j] = ScaledBPM[i][j+1];                  
    }
   
    BPM[i] = constrain(BPM[i], 0, 200);                     // limit the highest BPM value to 200
    float dummy = map(BPM[i], 0, 200, bpmY[i]+bpmHeight, bpmY[i]);   
    ScaledBPM[i][bpmWidth-1] = int(dummy);      
  }
}
// graph heart rate in small window
stroke(250, 0, 0);                          // color of heart rate graph
strokeWeight(2);                          // thicker line is easier to read
noFill();

for (int i=0; i<numSensors; i++) {
  beginShape();
  for (int j=0; j < bpmWidth; j++) {   
    vertex(j+bpmX, ScaledBPM[i][j]);                 
  }
  endShape();
}
}
void drawHeart(){
  //make the heart and make it beat
    fill(250,0,0);
    stroke(250,0,0);
  int bezierZero = 0;
  for(int i=0; i<numSensors; i++){
   
    heart[i]--;                   
    heart[i] = max(heart[i], 0);   
    if (heart[i] > 0) {            
      strokeWeight(8);         
    }
    smooth();   //draw hearts
    bezier(width-100, bezierZero+70, width-20, bezierZero, width, bezierZero+160, width-100, bezierZero+170);
    bezier(width-100, bezierZero+70, width-190, bezierZero, width-200, bezierZero+160, width-100, bezierZero+170);
    strokeWeight(1);          // reset the strokeWeight for next time
    bezierZero += bpmHeight+spacer;
  }
}



void listAvailablePorts(){
  //println(Serial.list());   
  serialPorts = Serial.list();
  fill(0);
  textFont(font,16);
  textAlign(LEFT);
  
  int yPos = 0;

  for(int i=numPorts-1; i>=0; i--){
    button[i] = new Radio(35, 95+(yPos*20),12,color(180),color(80),color(255),i,button);
    text(serialPorts[i],50, 100+(yPos*20));
    yPos++;
  }
  int p = numPorts;
   fill(233,0,0);
  button[p] = new Radio(35, 95+(yPos*20),12,color(180),color(80),color(255),p,button);
    text("Refresh Serial Ports List",50, 100+(yPos*20));

  textFont(font);
  textAlign(CENTER);
}

void autoScanPorts(){
  if(Serial.list().length != numPorts){
    if(Serial.list().length > numPorts){
      println("New Ports Opened!");
      int diff = Serial.list().length - numPorts;	
      serialPorts = expand(serialPorts,diff);
      numPorts = Serial.list().length;
    }else if(Serial.list().length < numPorts){
      println("Some Ports Closed!");
      numPorts = Serial.list().length;
    }
    refreshPorts = true;
    return;
}
}

void resetDataTraces(){
  for (int i=0; i<numSensors; i++) {
    BPM[i] = 0;
    for(int j=0; j<bpmWidth; j++){
      ScaledBPM[i][j] = bpmY[i] + bpmHeight;
    }
  }
  for (int i=0; i<numSensors; i++) {
    Sensor[i] = 512;
    for (int j=0; j<pulseWidth; j++) {
      RawPPG[i][j] = 1024 - Sensor[i]; 
    }
  }
}

void printDataToScreen(){ 
    fill(255);                                       
    text("Pulse Sensor to compare heart beats", 245, 30);    
    for (int i=0; i<numSensors; i++) {
      text("Sensor  " + (i+1), 1700, bpmY[i] + 220);
      text(BPM[i] + " BPM", 1700, bpmY[i] +185);         
      text("TBH " + TBH[i] + "mS", 1700, bpmY[i] + 160);

    }
}
class Radio {
  int _x,_y;
  int size, dotSize;
  color baseColor, overColor, pressedColor;
  boolean over, pressed;
  int me;
  Radio[] radios;

  Radio(int xp, int yp, int s, color b, color o, color p, int m, Radio[] r) {
    _x = xp;
    _y = yp;
    size = s;
    dotSize = size - size/3;
    baseColor = b;
    overColor = o;
    pressedColor = p;
    radios = r;
    me = m;
  }

  boolean pressRadio(float mx, float my){
    if (dist(_x, _y, mx, my) < size/2){
      pressed = true;
      for(int i=0; i<numPorts+1; i++){
        if(i != me){ radios[i].pressed = false; }
      }
      return true;
    } else {
      return false;
    }
  }

  boolean overRadio(float mx, float my){
    if (dist(_x, _y, mx, my) < size/2){
      over = true;
      for(int i=0; i<numPorts+1; i++){
        if(i != me){ radios[i].over = false; }
      }
      return true;
    } else {
      over = false;
      return false;
    }
  }

  void displayRadio(){
    noStroke();
    fill(baseColor);
    ellipse(_x,_y,size,size);
    if(over){
      fill(overColor);
      ellipse(_x,_y,dotSize,dotSize);
    }
    if(pressed){
      fill(pressedColor);
      ellipse(_x,_y,dotSize,dotSize);
    }
  }
}

//understood some of these concepts throught additional information on web
boolean spacePressed;
boolean onePressed;
boolean twoPressed;
boolean threePressed;
boolean fourPressed;
boolean fivePressed;
boolean sixPressed;
boolean sevenPressed;


void mousePressed(){
  if(!serialPortFound){
    for(int i=0; i<=numPorts; i++){
      if(button[i].pressRadio(mouseX,mouseY)){
        if(i == numPorts){
          if(Serial.list().length > numPorts){
            println("New Ports Opened!");
            int diff = Serial.list().length - numPorts;	
            serialPorts = expand(serialPorts,diff);
            //button = (Radio[]) expand(button,diff);
            numPorts = Serial.list().length;
          }else if(Serial.list().length < numPorts){
            println("Some Ports Closed!");
            numPorts = Serial.list().length;
          }else if(Serial.list().length == numPorts){
            return;
          }
          refreshPorts = true;
          return;
        }else

        try{
          port = new Serial(this, Serial.list()[i], 250000);
          delay(1000);
          println(port.read());
          port.clear();           
          port.bufferUntil('\n');  
          serialPortFound = true;
        }
        catch(Exception e){
          println("Couldn't open port " + Serial.list()[i]);
          fill(255,0,0);
          textFont(font,16);
          textAlign(LEFT);
          text("Couldn't open port " + Serial.list()[i],60,70);
          textFont(font);
          textAlign(CENTER);
        }
      }
    }
  }
}

void mouseReleased(){

}

void keyPressed(){
  if(key == ' '){
    spacePressed = true;
  }
  if(key == '1'){
    onePressed = true;
  }
  if(key == '2'){
    twoPressed = true;
  }
  if(key == '3'){
    threePressed = true;
  }
  if(key == '4'){
    fourPressed = true;
  }
  if(key == '5'){
    fivePressed = true;
  }
  if(key == '6'){
    sixPressed = true;
  }
  if(key == '7'){
    sevenPressed = true;
  }
  
 switch(key){
   case 's':    // pressing 's' or 'S' will take a jpg of the processing window
   case 'S':
     saveFrame("heartLight-####.jpg");    
     break;
   case 'r':
   case 'R':
     resetDataTraces();
     break;
   case ' ':

   default:
     break;
 }
}

void keyReleased(){
  spacePressed = false;
  onePressed = false;
  twoPressed = false;
  threePressed = false;
  fourPressed = false;
  fivePressed = false;
  sixPressed = false;
  sevenPressed = false;
}


void serialEvent(Serial port){
try{
   String inData = port.readStringUntil('\n');
   inData = trim(inData);                 

 for(int i=0; i<numSensors;i++){
   if (inData.charAt(0) == 'a'+i){           // leading 'a' for sensor data
     inData = inData.substring(1);           
     Sensor[i] = int(inData);                 
   }
   if (inData.charAt(0) == 'A'+i){           // leading 'A' for BPM data
     inData = inData.substring(1);           
     BPM[i] = int(inData);                   
     beat[i] = true;                         
     heart[i] = 20;                          
   }
 if (inData.charAt(0) == 'M'+i){             // leading 'M' means TBH data
     inData = inData.substring(1);           
     TBH[i] = int(inData);                   
   }
 }
  } catch(Exception e) {
  }

}