14 March 2021

NIME: Music Lunchbox


The music lunchbox uses the circuit playground express, servo, potentiometer, breadboard and assorted wires contained in a modified food container. The idea behind the design is recycling used food containers; while I’ve cleaned and repurposed these delivery style bowls in the past to hold other leftovers, I don’t usually find applications beyond food for the otherwise versatile containers. The cheap appearance contrasts with my own mental image of music boxes as antiques made of wood or metal. 


It features three melodies that can be played through the CPE speaker. Rotating the box on the x axis changes the song and pressing either the left or right button will start the selected audio. Each song has its own LED color to ensure the user knows when they’ve changed songs and which is currently selected in place of a screen or display.



The servo’s sounds serve to fill the empty air and let the user know they have yet to select a song; it serves to clarify if the play input has been received. Using the potentiometer interrupts the servo’s twitching occasionally. This is different from the intended use as I ran into issues with the pot readings after transferring it from the breadboard to wires. The output values of the pot (0-1023) are mapped 1:1 to the servo’s 0-180 degree rotation. 

///////////////////////////////// //      NIME // // by Julia Houha // ///////////////////////////////// /////////////////////////////////////////////////////////////// //          Instructions:          // // Press either left or right button         // // on CPE to play a song. Rotate left // // or right to change after hearing a // // song. Turn the pot to rotate the // // the servo.                  // ////////////////////////////////////////////////////////////// /////////////////////// // Libraries // /////////////////////// #include <Adafruit_CircuitPlayground.h> #include <Adafruit_Circuit_Playground.h> #include <Servo.h> /////////////////////// // Variables // /////////////////////// // outputs const int speaker = A0; // declares speaker Servo myServo; // declares servo #define POT A2 // defines potentiometer int value = 0; // creates pot value holder int currentSong = 0; // creates current song holder int timer = 0; // creates timer for millis bool songPlayed = true; // holds song until played int inc = 0; // holds rotation increase ///////////////// // Notes // ///////////////// #define NOTE_E4 329.63 #define NOTE_F4 349.23 #define NOTE_FS4 369.99 #define NOTE_G4 392.00 #define NOTE_AF4 415.30 #define NOTE_A4 440.00 #define NOTE_AS4 466.16 #define NOTE_B4 493.88 #define NOTE_C5 523.25 #define NOTE_DF5 554.37 #define NOTE_D5 587.33 #define NOTE_DS5 622.25 #define NOTE_E5 659.25 #define NOTE_F5 698.46 #define NOTE_G5 783.99 #define REST 0 //////////////////// // Melody // //////////////////// int melody1[] = { // Fukashigi no Carte - blue LEDs NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_C5, 4, REST, 8, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_C5, 4, REST, 8, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_G4, 3, NOTE_AF4, 2, REST, 8, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_C5, 4, REST, 8, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_DS5, 3, NOTE_DF5, 3, NOTE_C5, 1, REST, 8, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_C5, 4, REST, 8, NOTE_DS5, 3, NOTE_C5, 3, NOTE_AS4, 3, NOTE_G4, 3, NOTE_AF4, 3, NOTE_C5, 4, REST, 16, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_C5, 4, REST, 8, NOTE_F4, 8, NOTE_C5, 8, NOTE_AS4, 8, NOTE_AF4, 3, NOTE_E4, 3, NOTE_G4, 1, }; int melody2[] = { // Requiem - red LEDs NOTE_E4, 4, NOTE_B4, 2, NOTE_A4, 2, NOTE_D5, 2, NOTE_B4, 2, NOTE_G4, 2, NOTE_B4, 4, NOTE_A4, 4, NOTE_G4, 4, NOTE_FS4, 2, NOTE_E4, 4, NOTE_B4, 2, NOTE_A4, 2, NOTE_D5, 2, NOTE_B4, 2, NOTE_G4, 2, NOTE_B4, 4, NOTE_A4, 2, }; int melody3[] = { // Colors - green LEDs NOTE_G4, 8, NOTE_G5, 8, NOTE_F5, 8, NOTE_E5, 3, REST, 16, NOTE_E5, 8, NOTE_F5, 4, NOTE_E5, 4, NOTE_D5, 4, NOTE_C5, 4, NOTE_B4, 4, NOTE_G4, 8, NOTE_D5, 3, NOTE_D5, 4, NOTE_C5, 8, NOTE_D5, 4, NOTE_C5, 8, NOTE_D5, 8, NOTE_E5, 4, REST, 16, NOTE_E5, 4, NOTE_E5, 4, NOTE_F5, 8, NOTE_A4, 4, NOTE_D5, 4, NOTE_G5, 4, NOTE_F5, 8, NOTE_F5, 8, NOTE_E5, 4, NOTE_D5, 8, NOTE_F5, 8, NOTE_F5, 8, NOTE_E5, 2, }; // melody specific variables int tempo = 140; // sets the music pace int noteS = sizeof(melody1) / sizeof(melody1[0]) / 2; // holds size of melody1 int noteL = sizeof(melody2) / sizeof(melody2[0]) / 2; // holds size of melody2 int noteR = sizeof(melody3) / sizeof(melody3[0]) / 2; // holds size of melody3 int wholenote = (60000 * 4 / tempo); // calculates a whole note int divider = 0, noteDuration = 0; // calculates smaller notes ////////////////////////////////// // Main Functions // ////////////////////////////////// void setup() { // init serial and CPE library Serial.begin(9600); CircuitPlayground.begin(); // set input & output pins pinMode(speaker, OUTPUT); // sets speaker A0 pin as output myServo.attach(10); // attaches myServo to A3 pin pinMode(4, INPUT_PULLDOWN); // sets left button on pin 4 as input pinMode(5, INPUT_PULLDOWN); // sets right button on pin 5 as input } void loop() { int sound = CircuitPlayground.mic.soundPressureLevel(20); // record sound levels with mic value = analogRead(POT); // assign pot to value for servo mapping if (digitalRead(4) == 1 || digitalRead(5)) { // if either CPE button is pressed play current song if (currentSong == 0) { playMelody1(); songPlayed = true; } if (currentSong == 1) { playMelody2(); songPlayed = true; } if (currentSong == 2) { playMelody3(); songPlayed = true; } } moveServo(); // move servo via pot shuffle(); // change songs feedback(); // show which song is currently selected } /////////////////// // Shuffle // /////////////////// // Song select void shuffle() { float x = CircuitPlayground.motionX(); int flip = map(x, -15, 15, -4, 1); if (songPlayed == true) { if (flip == 0 || flip == -4) { currentSong++; if (currentSong >= 3) { currentSong = 0; } Serial.print("current song: "); Serial.println(currentSong); songPlayed = false; } } } //////////////////////// // Feedback // //////////////////////// // Song specific LEDs void feedback() { if (currentSong == 0) { for (int i = 0; i < 10; i++) { CircuitPlayground.setPixelColor(i, 60, 150, 240); } } if (currentSong == 1) { for (int j = 0; j < 10; j++) { CircuitPlayground.setPixelColor(j, 250, 60, 80); } } if (currentSong == 2) { for (int k = 0; k < 10; k++) { CircuitPlayground.setPixelColor(k, 125, 240, 60); } } } //////////////////////////////// // Play Melody 1 // //////////////////////////////// // plays melody 1 void playMelody1() { // iterates through notes for (int noteX = 0; noteX < noteS * 2; noteX = noteX + 2) { divider = melody1[noteX + 1]; if (divider > 0) { noteDuration = (wholenote) / abs(divider); } else if (divider < 0) { noteDuration = (wholenote) / abs(divider); noteDuration *= 1.5; } tone(speaker, melody1[noteX], noteDuration * 0.9); // plays note for 90% duration, 10% pause delay(noteDuration); // waits between notes noTone(speaker); // stops first note before playing next one } } //////////////////////////////// // Play Melody 2 // //////////////////////////////// // plays melody 2 void playMelody2() { // iterates through notes for (int noteX = 0; noteX < noteL * 2; noteX = noteX + 2) { divider = melody2[noteX + 1]; if (divider > 0) { noteDuration = (wholenote) / abs(divider); } else if (divider < 0) { noteDuration = (wholenote) / abs(divider); noteDuration *= 1.5; } tone(speaker, melody2[noteX], noteDuration * 0.9); // plays note for 90% duration, 10% pause delay(noteDuration); // waits between notes noTone(speaker); // stops first note before playing next one } } //////////////////////////////// // Play Melody 3 // //////////////////////////////// // plays melody 3 void playMelody3() { // iterates through notes for (int noteX = 0; noteX < noteR * 2; noteX = noteX + 2) { divider = melody3[noteX + 1]; if (divider > 0) { noteDuration = (wholenote) / abs(divider); } else if (divider < 0) { noteDuration = (wholenote) / abs(divider); noteDuration *= 1.5; } tone(speaker, melody3[noteX], noteDuration * 0.9); // plays note for 90% duration, 10% pause delay(noteDuration); // waits between notes noTone(speaker); // stops first note before playing next one } } /////////////////////////// // Move Servo // /////////////////////////// // moves the servo void moveServo() { int rotation = map(value, 0, 1023, 0, 180); // maps potentiometer to servo int ogPos; // holds pot's original position if (ogPos != rotation) { // if pot's position is new rotate servo if (millis() > timer + 15) { // replaces delay by comparing against millis if (rotation == 0)inc = 1; if (rotation == 180) inc = -1; myServo.write(rotation); timer = millis(); ogPos = rotation; Serial.println(value); Serial.println(ogPos); } } }

Would it have been more effective to use a different type of container? For instance a different shape, or completely opaque versus transparent?


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.