Midterm Project – RED MONSTER and the BLUE MONSTER

My main interest for this project was the transferring the feedback of one medium to another medium, especially dealing with pattern of sound created using the piezo disc. And, for the midterm project, I have created two monsters: the RED and the BLUE indicated by the color of their eyes, where the blue monster follows the pattern played by the red monster. On the interface, there are two buttons: the green and the blue. When the green button is pressed, the red monster’s LED lights up, the buzzer inside it activates. The duration of the rest period in between the press and the duration of the buzzer activated will be saved, and when the blue button is pressed, the blue monster will follow the pattern that the red monster has played in a continuous loop.

For the structure of the data for this project, I have used the STL library which encompasses vector. Since, an array has to be predetermined with its size, I could not implement the array as my duration container when the length of the pattern is indeterminable. Whereas, using a vector, I can just push_back the new duration at the end – which served as a perfect container for this project.

Initially, I had multiple issue with the difference in the speed of the patter played for either monsters. At first, the saved duration values of the Red Monster were incrementing too fast, which I fixed using the modulus of it by 2500 to slow down the increments. Then, when the Blue Monster was playing the saved pattern, the intended speed of the pattern and the actual speed was different. So, I had to include careful selection of delay values to match them.

An interesting note about the project was that the enclosure was done with a transparent acrylic with the base being open on the sides. According to Critical Interface Toolbox by Joana Moll and Andrea Noni, one of the highlights of the definition of interface was “Users are entitled to know what the interface hides. Access to knowledge is a fundamental right“. Plus, after reading through different examples of the enclosure boxes, I was intrigued by the design of open-sides boxes, especially the “Moshi Moshi” created by Aaron. Therefore, I came to a conclusion to make the container of the project transparent for the audience to see what is happening underneath the system.

[Quick Play-through of the Project]

[Source Code for the Project]

#include <ArduinoSTL.h>

// ===== Declaring Variable Pin ===== //
const int triggerPin = 2;
const int buttonPin = 7;

const int buzzerOnePin = 12;
const int buzzerTwoPin = 13;

const int ledPinOne = 3;
const int ledPinTwo = 4;

const int ledPinThree = 10;
const int ledPinFour = 11;

// ===== Declaring Initial State ===== //
int prevPadState = 0;
int currentPadState = 0;

int currentTriggerState;
int prevTriggerState;

int savedRestDuration = 0;
int savedPlayedDuration = 0;

// Time Duration to slow down the accumulation of saved duration for the later loop
long timeDuration = 0;

// Conditions to check which loop to proceed:
// 1. TRUE :: BLUE MONSTER playing the saved duration of the vector
// 2. FALSE :: RED MONSTER playing and recording the pattern played into the vector
bool playLoopState = false;

unsigned long prevTime = 0;
unsigned long currentTime = 0;

// Interval Index is set as 1 so that when the trigger button is pressed,
// the savedNotes vector is played in the beginning disregarding the first rest period.
int intervalIndex = 1;

int resetIndex = 0;

// The container vector of durations for rest and playing of the note;
// ============================
// The even number index - REST;
// The odd number index - PLAY;
// ============================

std::vector<int> savedNotes;
 
void setup() {
  //Serial Port begin
  Serial.begin (9600);

  // RED MONSTER Buzzer
  pinMode(buzzerOnePin, OUTPUT);

  // BLUE MONSTER Buzzer
  pinMode(buzzerTwoPin, OUTPUT);

  // button - RED MONSTER
  // trigger - triggers the BLUE MONSTER to mimic the pattern of the RED MONSTER
  pinMode(buttonPin, INPUT);
  pinMode(triggerPin, INPUT);

  // RED MONSTER LEDs
  pinMode(ledPinOne, OUTPUT);
  pinMode(ledPinTwo, OUTPUT);

  // BLUE MONSTER LEDs
  pinMode(ledPinThree, OUTPUT);
  pinMode(ledPinFour, OUTPUT);
}
 
void loop() {

  currentTriggerState = digitalRead(triggerPin);
  currentPadState = digitalRead(buttonPin);
  
// ========================================================= //

  if (!playLoopState) {  
    if ((timeDuration%2500) == 0) {
      if (currentPadState == 1 && prevPadState == 1) {
        /*
         *  Button is being pressed = the buzzer is playing
         */
        Serial.print("Keep Playing!: ");
        tone(buzzerOnePin, 100);
        savedPlayedDuration++;
        Serial.println(savedPlayedDuration);
      }
  
      if (currentPadState == 0 && prevPadState == 0) {
        /*
         *  Button is not being pressed = the buzzer is resting
         */
        Serial.print("Keep Resting!: ");
        noTone(buzzerOnePin);
        savedRestDuration++;
        Serial.println(savedRestDuration);
      }
  
      if (currentPadState == 1 && prevPadState == 0) {
        /*
         *  The first loop when the button is pressed. This means that prior to the button press,
         *  the buzzer was resting. So I saved the accumulated duration of rest at this point.
         */
        tone(buzzerOnePin, 100);
        prevPadState = currentPadState; 

        // Start of playing duration;
        savedPlayedDuration++;

        digitalWrite(ledPinOne, HIGH);
        digitalWrite(ledPinTwo, HIGH);

        Serial.print("SAVED REST NOTE :");
        Serial.println(savedRestDuration);

        // Push the rest duration into the vector & reset the duration;
        savedNotes.push_back(savedRestDuration);
        savedRestDuration = 0;
        
      } else if (currentPadState == 0 && prevPadState == 1) {
         /*
         *  The first loop when the button is released. This means that prior to the button press,
         *  the buzzer was playing. So I saved the accumulated duration of playing at this point.
         */
        noTone(buzzerOnePin);
        prevPadState = currentPadState;

        // Start of rest duration;
        savedRestDuration++;

        digitalWrite(ledPinOne, LOW);
        digitalWrite(ledPinTwo, LOW);

        Serial.print("SAVED PLAY NOTE :");
        Serial.println(savedPlayedDuration);

        // Push the played duration into the vector & reset the duration;
        savedNotes.push_back(savedPlayedDuration);
        savedPlayedDuration = 0;
      }
    }
    
// ========================================================= //

  } else { 
    if (intervalIndex < savedNotes.size()) {
    /* ==========================================================
     * When the blue-button is pressed, the loop iterates through
     * the savedNotes vector from the designated interval index 
     * to the size of the vector.
     * ========================================================== */ 
      Serial.println(savedNotes[intervalIndex]);
      
      if ((currentTime) - (prevTime) <= savedNotes[intervalIndex]) {
        if ((intervalIndex % 2) == 0) {
          /* =========================================================
           * When the index of the vector saveNotes is an EVEN number,
           * the value of the vector at that index is the duration of
           * how long the "rest" period was. The loop is repeated until
           * currentTime - prevTime is equal to or larger than the
           * duration value of the saved rest.
           * ========================================================= */ 
          Serial.println("REST");
          noTone(buzzerTwoPin);
          digitalWrite(ledPinThree, LOW);
          digitalWrite(ledPinFour, LOW);
          delay(125);
        } else if ((intervalIndex % 2) == 1) {
          /* ========================================================
           * When the index of the vector saveNotes is an ODD number,
           * the value of the vector at that index is the duration of
           * how long the "played" period was. The loop is repeated 
           * until currentTime - prevTime is equal to or larger than 
           * the duration value of the saved rest.
           * ======================================================== */ 
          Serial.println("PLAYED");
          tone(buzzerTwoPin, 500);
          digitalWrite(ledPinThree, HIGH);
          digitalWrite(ledPinFour, HIGH);
          delay(125);
        }
      } else {
        /* ==========================================================
           * When the saved duration of the note/rest is done playing,
           * it will move on to the next index of the vector while
           * resetting the time.
           * ======================================================== */ 
        Serial.print("Next Index: ");
        Serial.println(intervalIndex);
        prevTime = currentTime;
        intervalIndex++;
      }
      
    } else {
       /* =========================================================
       * All the played/saved notes were iterated, repeating the
       * loop to play from the beginning of the vector
       * ========================================================= */ 
      Serial.println("Loop Finished & REPEAT");
      intervalIndex = 0;
      currentTime = 0;
      prevTime = 0;
    }
    
    currentTime++;
  }

  if (currentTriggerState == HIGH && prevTriggerState == LOW) {
    /* ================================
     * For the reset index:
     * 1. When the reset button is pressed for the first time, the index is    0 - signnaling the start the pattern loop for BLUE MONSTER
     * 2. When the reset button is pressed for the second time, the index is 1 - signaling the reset of the patter loop and go back to recording with the RED MONSTER
     * ================================*/
    if((resetIndex % 2) == 1) {
      Serial.println("CLEAR");
      
      // The vector is reset to be ready for next set of inputs from the RED MONSTER
      savedNotes.clear();
      intervalIndex = 1;

      savedRestDuration = 0;
      savedPlayedDuration = 0;

      noTone(buzzerTwoPin);
      noTone(buzzerTwoPin);

      digitalWrite(ledPinOne, LOW);
      digitalWrite(ledPinTwo, LOW);
      digitalWrite(ledPinThree, LOW);
      digitalWrite(ledPinFour, LOW);
    } 
    playLoopState = !playLoopState;
    resetIndex++;
    prevTriggerState = currentTriggerState;
  } else {
    prevTriggerState = currentTriggerState;
  }

  timeDuration++;
}

 

Leave a Reply