I welcome comments and suggestions.
In this project, I learned how to utilize pull-up resistors, and how to drive the passive buzzer to play specific notes/tones. I did not use the tone() module that everyone is fond of, as I prefer to figure out how things work on my own. I also dove into drawing my first schematic for this project. It may not be perfect and complete, but I think it gets the point across.
The project is built on the Mega2560 board, but should work on the UNO as well. The code supports the regular CDEFGAB notes, as well as their sharp versions. However, due to lack of buttons in my inventory, the sharp functionality is disabled in the code. A person just needs to uncomment all code related to the sharps, and assign proper pins, then add buttons to support those notes. * Note: I don't think the UNO has enough input pins to support sharp notes.
Other features:
- Octave up and down, via 2 buttons.
- Records as you play, allowing you to play back your recording. Supports up to 512 notes array, though you can adjust this to play more if you wish.
- Tempo can be changed via the tempoMs variable in code.
Code:
// notes
int cPin = 2; //int cSharpPin = 3;
int dPin = 3; //int dSharpPin = 5;
int ePin = 4;
int fPin = 5; //int fSharpPin = 8;
int gPin = 6; //int gSharpPin = 10;
int aPin = 7; //int aSharpPin = 12;
int bPin = 8;
// octave
int octaveDownPin = 9;
int octaveUpPin = 10;
int octave = 4;
int minOctave = 2;
int maxOctave = 6;
// speaker/buzzer
int spkPin = 11;
// playback
int playbackPin = 12;
String recordedNote[512];
int recordedNoteIndex = 0;
int tempoMs = 250; // 1/4 beat tempo, milliseconds
void setup() {
pinMode(cPin, INPUT); //pinMode(cSharpPin, INPUT);
pinMode(dPin, INPUT); //pinMode(dSharpPin, INPUT);
pinMode(ePin, INPUT);
pinMode(fPin, INPUT); //pinMode(fSharpPin, INPUT);
pinMode(gPin, INPUT); //pinMode(gSharpPin, INPUT);
pinMode(aPin, INPUT); //pinMode(aSharpPin, INPUT);
pinMode(bPin, INPUT);
pinMode(octaveDownPin, INPUT);
pinMode(octaveUpPin, INPUT);
pinMode(spkPin, OUTPUT);
pinMode(playbackPin, INPUT);
Serial.begin(9600);
delay(500);
Serial.println("Ready! Press RESET to clear recording.");
}
void loop() {
// octave down
if (digitalRead(octaveDownPin) == LOW) {
setOctave(octave - 1);
addToRecordedNotes("O-");
while (digitalRead(octaveDownPin) == LOW) {}
}
// octave up
if (digitalRead(octaveUpPin) == LOW) {
setOctave(octave + 1);
addToRecordedNotes("O+");
while (digitalRead(octaveUpPin) == LOW);
}
// notes
int freq = 0;
String note = "";
if (digitalRead(cPin) == LOW) { note = "C"; }
//if (digitalRead(cSharpPin) == LOW) { note = "C#"; }
if (digitalRead(dPin) == LOW) { note = "D"; }
//if (digitalRead(dSharpPin) == LOW) { note = "D#"; }
if (digitalRead(ePin) == LOW) { note = "E"; }
if (digitalRead(fPin) == LOW) { note = "F"; }
//if (digitalRead(fSharpPin) == LOW) { note = "F#"; }
if (digitalRead(gPin) == LOW) { note = "G"; }
//if (digitalRead(gSharpPin) == LOW) { note = "G#"; }
if (digitalRead(aPin) == LOW) { note = "A"; }
//if (digitalRead(aSharpPin) == LOW) { note = "A#"; }
if (digitalRead(bPin) == LOW) { note = "B"; }
if (note != "") {
playNote(note);
addToRecordedNotes(note);
}
// playback recording
if (digitalRead(playbackPin) == LOW) {
while (digitalRead(playbackPin) == LOW) {}
playRecorded();
}
}
// play back recorded notes
void playRecorded() {
if (recordedNoteIndex == 0) return;
// print all notes from array
Serial.print("\nPlaying: ");
for(int i = 0; i < recordedNoteIndex; i++) { Serial.print(recordedNote[i] + " "); }
Serial.println();
octave = 4;
// play each note from array, display note currently being played
for (int i = 0; i < recordedNoteIndex; i++) {
String note = recordedNote[i];
if (note == "O+") { setOctave(octave + 1); Serial.print(note + " "); }
else if (note == "O-") { setOctave(octave - 1); Serial.print(note + " "); }
else { playNote(note); }
}
octave = 4;
Serial.println("\nEnd Playback");
}
// play a specific note
void playNote(String note, int durationMs) {
note.toUpperCase();
Serial.print(note + " ");
float freq;
if (note == "C") freq = 16.35;
if (note == "C#") freq = 17.32;
if (note == "D") freq = 18.35;
if (note == "D#") freq = 19.45;
if (note == "E") freq = 20.60;
if (note == "F") freq = 21.83;
if (note == "F#") freq = 23.12;
if (note == "G") freq = 24.50;
if (note == "G#") freq = 25.96;
if (note == "A") freq = 27.50;
if (note == "A#") freq = 29.14;
if (note == "B") freq = 30.87;
// update frequency for current octave
freq = freq * pow(2, octave + 1); // calc freq for octave
// convert note frequency to speaker cycle value (microseconds (us))
int cycleUs = (1000 / freq) * 1000;
// get number of cycles
long cycles = durationMs * 1000L / cycleUs;
// cycle speaker
for (long i = 0; i < cycles; i++) {
digitalWrite(spkPin, HIGH);
delayMicroseconds(cycleUs);
digitalWrite(spkPin, LOW);
delayMicroseconds(cycleUs);
}
}
void playNote(String note) { playNote(note, tempoMs); } // play at default tempo
// set octave, within bounds
void setOctave(int value) {
octave = value;
if (octave < minOctave) octave = minOctave;
if (octave > maxOctave) octave = maxOctave;
}
// add a note to recording array
void addToRecordedNotes(String note) {
recordedNote[recordedNoteIndex] = note;
recordedNoteIndex++;
}
Physical build:
Schematic:
Edited: I accidentally switched the connections on the buzzer. Fixed.

