Team Members: Evan Strasnick, Joseph Bolling, Xin Yang Yak, Jacob Simon
Group Number: 17
What We Built: We built a system that overlays tunes on top of a bass beat, using an accelerometer to select notes from within a given chord so that the result is always in tune for a specific key. A rotary pot allows the user to control the tempo, a push button on the larger breadboard varies the chord being used – either to toggle to the next set of notes or to modulate the sound through a continuous hold, the accelerometer picks out a note from within the currently selected chord, and the push button on the hand-held component plays the tune. To play our musical instrument, the user simply holds the hand-held controller (the smaller breadboard) in one hand and presses the button to create sound while controlling pitch via rotation. The user can also vary the tempo with the Tempo Knob and change the chord by pressing the Chord Progression button. For our demonstration, we chose a CM, FM, GM chord progression, but the instrument could theoretically support any arrangement or number of chords the user desires. This instrument was not only a success in terms of offering a number of ways in which the user could create an original beat, but it was also surprisingly addicting to play. We would have liked to use more speaker elements to offer different instrumental options as well.
Prototypes:
1) Our first prototype was a simple mapping of the accelerometer tilt to allow the user to play melodies over a certain range of musical pitches. While this offered the most control over pitch in theory, we wanted the user to not have to worry so much about tilting correctly for the pitches that they wanted, allowing them to focus more on the beat that they were dropping. This philosophy inspired our next design… http://www.youtube.com/watch?v=2g6CM7rNnuk&feature=youtu.be
2) Our second prototype instead preserved the fun of using the accelerometer to play, but aided the user by mapping its output to the notes within specific chords. After adding in the push button users were able to program in their own chord progressions for a given song and then simply iterate through them. http://www.youtube.com/watch?v=VkYfAKPzM4Q&feature=youtu.be
3) Our third prototype added in a constant bassline, which was always tuned to match the accelerometer’s output, keeping things easy for the user. Further, we added a potentiometer which allowed the user to control tempo. http://www.youtube.com/watch?v=C6CM0272D44&feature=player_detailpage#t=23s
Final Performance: Entitled “Lab 2 in A Minor,” this piece is a satire on satire, and a celebration of celebratory pieces (and poor percussionists). Enjoy: http://www.youtube.com/watch?v=QrFFuBdYg8k&feature=youtu.be
Parts Used:
Instructions to Recreate:
To build our instrument, mount the accelerometer and a push button on a small breadboard or other device that can be held and manipulated with one hand. Connect the accelerometer Vin, 3Vo, Gnd, and Yout to the A0, A1, A2, and A4 pins on the Arduino, respectively. Ground one terminal on the pushbutton, and connect the other to the Arduino’s digital pin 2. Be sure to keep your wiring tight on this section-You may want to bundle your wires out of the way and secure the connections with electrical tape or solder, as this part of the device will be moving a lot as you play.
Connect the buzzer in series with a 220Ω resistor between ground and digital pin 3. Use alligator clips to connect the piezo element between digital pin 3 and ground. These two components will produce your sound, so feel free to experiment with different physical setups to see what kind of tonality you can get- we found that covering the sound hole on our buzzer actually made it considerably louder.
Mount the second pushbutton and the potentiometer on a separate breadboard. Ground one leg of the pushbutton, and connect the other to digital pin 4 on the Arduino. Connect the center leg of the potentiometer to pin A5, and connect the outer two legs to the Arduino’s +5V and Gnd pins. When wiring this section, try to keep your wiring tight and out of the way- you’ll want to have uninhibited access to the pushbutton and potentiometer as you play. Then just upload our code to your Arduino and have fun!
Source Code:
/* :::::::::::::: PIN LAYOUT :::::::::::::: */ // Accelerometer's power & ground pins const int groundpin = A2; const int powerpin = A0; // Accelerometer's Y axis const int ypin = A4; const int tempopin = A5; // Speaker pins === const int piezopin = 3; const int buzzerpin = 5; // Button pins === const int buttonpin = 2; const int chordpin = 4; int** progression; int chordindex; int basscounter; boolean basson; boolean buttonpressed; /* :::::::::::::: MUSIC VARS :::::::::::::: */ int scaleN = 8; int chordN = 4; // C Major Scale: c, d, e, f, g, a, b, c int CMajorScale[] = {3830, 3400, 3038, 2864, 2550, 2272, 2028, 1915}; char CMajorScaleNotes[] = "cdefgabc"; // C Major Chord: c, e, g, c int CMajor[] = {3830, 3038, 2550, 1915}; char CMajorNotes[] = "cegc"; // G Major Chord: g, b, d, f int GMajor[] = {5100, 4056, 3400, 2864}; char GMajorNotes[] = "gbdf"; // F Major Chord: f, a, c, f int FMajor[] = {2864, 2272, 1915, 1432}; char FMajorNotes[] = "facd"; // A Minor Chord: a, c, e, g int AMinor[] = {4544, 3830, 3038, 2550}; char AMinorNotes[] = "aceg"; int* CFCAC[] = {CMajor, FMajor, CMajor, AMinor, CMajor}; int* CFCGC[] = {CMajor, FMajor, CMajor, GMajor, CMajor}; /* :::::::::::::: SETUP :::::::::::::: */ void setup() { // initialize the serial communications: Serial.begin(9600); pinMode(groundpin, OUTPUT); pinMode(powerpin, OUTPUT); digitalWrite(groundpin, LOW); digitalWrite(powerpin, HIGH); // Input pins pinMode(ypin, INPUT); pinMode(buttonpin, INPUT); digitalWrite(buttonpin, HIGH); pinMode(chordpin, INPUT); digitalWrite(chordpin, HIGH); // Output pins pinMode(buzzerpin, OUTPUT); pinMode(piezopin, OUTPUT); progression = CFCGC; chordindex = 0; basson = true; basscounter = 0; } /* :::::::::::::: FUNCTIONS :::::::::::::: */ // === #define THRESHOLD 270 // Returns a value between lo and hi // by taking in and subtracting the threshold int mapToRange(int in, int lo, int hi) { // Subtract threshold value int result = in - THRESHOLD; if (result > hi) return hi; else if (result < lo) return lo; else return result; } // int convertToTone(float value, float range, int* notes, int n) { // do this until we find something better if (value >= range) return notes[n-1]; int i = (value / range) * n; return notes[i]; } // Plays a note with period through speaker on pin void playTone(int period, int duration, int pin) { // Time between tone high and low int timeDelay = period / 2; for (long i = 0; i < duration * 1000L; i += period * 2) { digitalWrite(pin, HIGH); delayMicroseconds(timeDelay); digitalWrite(pin, LOW); delayMicroseconds(timeDelay); } } void playTwoTones(int period, int duration, int pin, int bassperiod, int basspin) { // Time between tone high and low int timeDelay = period / 2; for (long i = 0; i < duration * 1000L; i += period * 2) { if (buttonpressed) { digitalWrite(pin, HIGH); } if (basson) { digitalWrite(basspin, HIGH); } delayMicroseconds(timeDelay); if (basson) { digitalWrite(basspin, LOW); } if (buttonpressed) { digitalWrite(pin, LOW); } delayMicroseconds(timeDelay); } } // Not using this right now but keeping for reference void playNote(char note, int duration) { char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' }; int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 }; // play the tone corresponding to the note name for (int i = 0; i < 8; i++) { if (names[i] == note) { playTone(tones[i], duration, buzzerpin); } } } /* :::::::::::::: MAIN LOOP :::::::::::::: */ void loop() { basscounter++; if (basscounter == 4) { basscounter = 0; } if (basscounter == 0) { basson = true; } else basson = false; if (digitalRead(chordpin) == LOW) { chordindex++; if (chordindex == 4) chordindex = 0; } // Play sounds if the button is pressed buttonpressed = (digitalRead(buttonpin) == LOW); Serial.println("Button pressed!"); // Analog Read int analog = analogRead(ypin); int tempo = analogRead(tempopin) + 10; // Debug: Print the analogRead value Serial.print("AnalogRead: "); Serial.println(analog); // Map the Y-axis value to the range [0, 250] float yValue = mapToRange(analog, 0, 135); // Calculate the tone (period value) int tone = convertToTone(yValue, 135, progression[chordindex], chordN); int basstone = progression[chordindex][0]; // Debug: Print out the yValue and tone (period) Serial.print("yValue: "); Serial.println(yValue); Serial.print("tone: "); Serial.println(tone); Serial.println("------------"); // Actually produce some sound! playTwoTones(tone, 100, piezopin, basstone, buzzerpin); // Delay before next reading: delay(tempo); }