Piezo buzzers are one of the simplest things to add to any project, easily giving you a non-visual alert system. At its most basic, they can be as simple as blinking an LED - just turn a digital pin on and off on your microcontroller, replace the LED with a buzzer, and you have an audible warning alarm. If you’ve worked with the Arduino “tone” library, then you know that by controlling the frequency sent to the buzzer, you can change the pitch and actually play tunes. Of course, one of the shortcomings is the fact that you can only play one note at a time. You could connect multiple buzzers to multiple pins, but it’s still only possible to play one sound, from one buzzer, at a time.
The new SparkFun Qwiic Buzzer addresses those issues. By adding a little circuitry to the board, including an ATtiny84, and making it controllable via I2C, we’ve created what one Funion has called “the most over-engineered buzzer in the world.” However, for someone like me who might want to do more than just single volume, monophonic buzzer alerts, this new buzzer that's capable of daisy-chaining and playing up to 128 at a time is a dream come true.
HOW IT WORKS
If you’ve worked with the tone library, then working with our Qwiic buzzer will feel very familiar. While there are a few different ways to create sounds, the easiest is to create an integer array for both the notes and their duration. Then it’s just a matter of creating a “for” loop, matching the number of loops to the number of notes in your tune.
AN EXAMPLE TO GET YOU STARTED
When I started working on the demo for the Qwiic Buzzer Video, I thought, what should be “Hello World!” of buzzers? The “Blink” sketch? The only logical solution seemed to be the Super Mario Brothers theme.
I used three voices for this demo, so the first thing we need to do is change the I2C addresses on two of the boards. This is easily done using example 5. Then it’s on to the main sketch. After importing the Qwiic Buzzer library, I created instances for each of the three buzzers. You can name each one whatever works for you - voice1, voice2, voice3; high, medium, low; whatever works for your brain. For this example I went with melodyBuzzer, harmonyBuzzer, and bassBuzzer. Next, I created arrays for the notes of each of the three voices, and the durations of each note. Depending on the length of your song, this can wind up taking up most of your memory. While this example will for on a SparkFun Redboard or Arduino Uno, if you want to expand on this, or have multiple song options like I did in the video, you’ll definitely want to use a board with more memory, like a Redboard Artemis or one of our ESP32 boards. The setup loop is just what you’d expect - initiate (.begin) each buzzer instance, make sure they’re recognized, and you’re good to go.
You’ll notice that the bulk of the playing instructions happen in a separate function, called void play_melody(). Once we've established the notes and their durations, that all just gets fed into this function, and the song plays!
WHAT THE CODE LOOKS LIKE
/*
* SparkFun Qwiic Buzzer Polyphony Demo
*
* This example shows off the Qwiic Buzzer's ability
* to comtrol multiple buzzers simultaneously by
* playing a 3-part arrangement of a little bit of
* the Super Mario Bros Theme.
*
* By Rob Reynolds @ SparkFun Electronics
* February 2024
*
* Hardware connections:
* Connect three (3) SparkFun Qwiic Buzzers to you
* microcontroller via the Qwiic connectors.
*
* SparkFun code, firmware, and software is released under the MIT License.
* Please see LICENSE.md for further details.
*
* This code is released under the Beerware License. If you find this code
* useful, and see me or any other Funion at the local, buy us a beer!
*
* Distributed as-is, with no warranty *
*
*/
#include <SparkFun_Qwiic_Buzzer_Arduino_Library.h> // Import the library for the Qwiic Buzzer
QwiicBuzzer melodyBuzzer; //0x34 (default)
QwiicBuzzer harmonyBuzzer; //0x35 (previously changed)
QwiicBuzzer bassBuzzer; //0x36 (previously changed)
// notes in the melody:
int melody[] = {
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_REST, // silence (aka "rest")
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_REST, // silence (aka "rest")
// "A" section starts here***********************************
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST, // silence (aka "rest")
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_REST, // silence (aka "rest")
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_REST, // silence (aka "rest")
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_AS4,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_G4, //TRIPLETS START
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_A5,
SFE_QWIIC_BUZZER_NOTE_F5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_REST,
// "A" section repeat starts here ***********************
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_AS4,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_G4, //TRIPLETS START
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_A5,
SFE_QWIIC_BUZZER_NOTE_F5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_REST,
//"B" Section starts here**************************
SFE_QWIIC_BUZZER_NOTE_REST, //measure 7
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_FS5,
SFE_QWIIC_BUZZER_NOTE_F5,
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 8
SFE_QWIIC_BUZZER_NOTE_GS4,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 9
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_FS5,
SFE_QWIIC_BUZZER_NOTE_F5,
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 10
SFE_QWIIC_BUZZER_NOTE_C6,
SFE_QWIIC_BUZZER_NOTE_C6,
SFE_QWIIC_BUZZER_NOTE_C6,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 11
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_FS5,
SFE_QWIIC_BUZZER_NOTE_F5,
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 12
SFE_QWIIC_BUZZER_NOTE_GS4,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 13
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C5, //measure 14
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST,
};
// Notes in the harmony
int harmony[] = {
SFE_QWIIC_BUZZER_NOTE_FS4,
SFE_QWIIC_BUZZER_NOTE_FS4,
SFE_QWIIC_BUZZER_NOTE_FS4,
SFE_QWIIC_BUZZER_NOTE_FS4,
SFE_QWIIC_BUZZER_NOTE_FS4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
// "A" section starts here*********************************
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_D4,
SFE_QWIIC_BUZZER_NOTE_CS4,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_C4, //TRIPLETS START
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_D4,
SFE_QWIIC_BUZZER_NOTE_REST,
// "A" section repeat starts here*********************************
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_D4,
SFE_QWIIC_BUZZER_NOTE_CS4,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_C4, //TRIPLETS START
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_A4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_D4,
SFE_QWIIC_BUZZER_NOTE_REST,
//"B" Section starts here**************************
SFE_QWIIC_BUZZER_NOTE_REST, //measure 7
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 8
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 9
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 10
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_G5,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 11
SFE_QWIIC_BUZZER_NOTE_E5,
SFE_QWIIC_BUZZER_NOTE_DS5,
SFE_QWIIC_BUZZER_NOTE_D5,
SFE_QWIIC_BUZZER_NOTE_B4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C5,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 12
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_G4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_REST, //measure 13
SFE_QWIIC_BUZZER_NOTE_GS4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E4, //measure 14
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_REST,
};
// notes in the bass:
int bass[] = {
SFE_QWIIC_BUZZER_NOTE_D3,
SFE_QWIIC_BUZZER_NOTE_D3,
SFE_QWIIC_BUZZER_NOTE_D3,
SFE_QWIIC_BUZZER_NOTE_D3,
SFE_QWIIC_BUZZER_NOTE_D3,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_G2,
SFE_QWIIC_BUZZER_NOTE_REST,
// "A" section starts here**********************************
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_F3,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_FS3,
SFE_QWIIC_BUZZER_NOTE_F3,
SFE_QWIIC_BUZZER_NOTE_E3, //TRIPLETS START
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_D4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_A3,
SFE_QWIIC_BUZZER_NOTE_B3,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
// "A" section starts here**********************************
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_E3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_C3,
SFE_QWIIC_BUZZER_NOTE_REST,
SFE_QWIIC_BUZZER_NOTE_F3,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_FS3,
SFE_QWIIC_BUZZER_NOTE_F3,
SFE_QWIIC_BUZZER_NOTE_E3, //TRIPLETS START
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_F4,
SFE_QWIIC_BUZZER_NOTE_D4,
SFE_QWIIC_BUZZER_NOTE_E4,
SFE_QWIIC_BUZZER_NOTE_C4,
SFE_QWIIC_BUZZER_NOTE_A3,
SFE_QWIIC_BUZZER_NOTE_B3,
SFE_QWIIC_BUZZER_NOTE_G3,
SFE_QWIIC_BUZZER_NOTE_REST,
// "B" section starts here ***************************************
// Numbers indicate note durations, just for my reference when writing
SFE_QWIIC_BUZZER_NOTE_C3, //4 measure 7
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_G3, //8
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_C4, //4
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_F3, //4 measure 8
SFE_QWIIC_BUZZER_NOTE_REST, //16
SFE_QWIIC_BUZZER_NOTE_REST, //16
SFE_QWIIC_BUZZER_NOTE_C4, //8
SFE_QWIIC_BUZZER_NOTE_C4, //8
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_F3, //8
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_C3, //4 measure 9
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_G3, //8
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_G3, //8
SFE_QWIIC_BUZZER_NOTE_C4, //8
SFE_QWIIC_BUZZER_NOTE_REST, //2 measure 10
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_G3, //4
SFE_QWIIC_BUZZER_NOTE_C3, //4 measure 11
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_G3, //8
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_C4, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_F3, //4 measure 12
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_C4, //8
SFE_QWIIC_BUZZER_NOTE_C4, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_F3, //4
SFE_QWIIC_BUZZER_NOTE_REST, //4
SFE_QWIIC_BUZZER_NOTE_C3, //4 measure 13
SFE_QWIIC_BUZZER_NOTE_GS3, //4
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_AS3, //4
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_C4, //4 measure 14
SFE_QWIIC_BUZZER_NOTE_REST, //8
SFE_QWIIC_BUZZER_NOTE_G3, //8
SFE_QWIIC_BUZZER_NOTE_G3, //4
SFE_QWIIC_BUZZER_NOTE_C3, //4
};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int marioNoteDurations[] = {
8, 4, 4, 8, 4, 4, 4, 4, 4,
4, 8, 4, 8, 4, 8, 4, 4, 8, 4, 6, 6, 6, 4, 8, 4, 4, 8, 8, 4, 8,
4, 8, 4, 8, 4, 8, 4, 4, 8, 4, 6, 6, 6, 4, 8, 4, 4, 8, 8, 4, 8, //start "B" section next line
4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8, 8, 4, 8, 4, 4,
4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 4, 8, 4, 8, 8, 4, 4
// The extended spaces above aren't necessary, I use them to separate measures
// simply to help me keep the music more clear. Very helpful for debugging!
};
void setup() {
Serial.begin(115200);
Serial.println("Qwiic Buzzer Super Mario Bros Sample");
Wire.begin(); //Join I2C bus
melodyBuzzer.begin(0x34);
harmonyBuzzer.begin(0x35);
bassBuzzer.begin(0x36);
/*
// These are good for testing, I commented them out when I moved the project to stand-alone
//check if buzzer will connect over I2C
if (buzzer1.begin() == false) {
Serial.println("Buzzer 1 did not connect! Freezing.");
while (1);
}
else if (buzzer2.begin() == false) {
Serial.println("Buzzer 2 did not connect! Freezing.");
while (1);
}
else if (buzzer3.begin() == false) {
Serial.println("Buzzer 3 did not connect! Freezing.");
while (1);
}
*/
Serial.println("Buzzers connected.");
Serial.println("Buzzing Melody now...");
play_melody();
}
void loop() {
// do nothing here
// we just play the melody once during setup above.
}
void play_melody()
{
// iterate over the notes of the melody:
for (int thisNote = 0; thisNote < 103; thisNote++) { // 51 for A section only (repeated), 97 for entire demo for total melody/harmony notes, add 8 rests to bass
// to calculate the note duration, take one second divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int melodyNoteDuration = 1000 / marioNoteDurations[thisNote]; // change number to change tempo. <1000 = faster; >1000 = slower
melodyBuzzer.configureBuzzer(melody[thisNote], melodyNoteDuration, SFE_QWIIC_BUZZER_VOLUME_MAX);
melodyBuzzer.on();
harmonyBuzzer.configureBuzzer(harmony[thisNote], melodyNoteDuration, SFE_QWIIC_BUZZER_VOLUME_MAX);
harmonyBuzzer.on();
bassBuzzer.configureBuzzer(bass[thisNote], melodyNoteDuration, SFE_QWIIC_BUZZER_VOLUME_MAX);
bassBuzzer.on();
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = melodyNoteDuration * 1.30;
delay(pauseBetweenNotes);
}
}
For musicians starting out in coding, this may seem a bit overwhelming. If you're a coder without much of a background in music, this may seem equally daunting. Below is a graphic showing the notes and their octaves. You can extend below and above the notes shown, but that should give you a good starting point. Note also that we don't use F#, G#, etc, rather we use FS, GS, etc, because of the #'s place in C++.
NOW IT'S YOUR TURN TO CREATE
This sketch is a great starting point. From here, all you need to do to create a new tune is change the values of the notes and their durations. And while that may seem like a lot - each note requires a line that looks like
SFE_QWIIC_BUZZER_NOTE_C4,
A couple of things that I found extremely helpful during the process include commenting measure numbers when creating the "notes" integers, or at least commenting very clear sections. You'll notice in the above sketch that I comment when each new section begins, and when the triplets start in the "A" section. In defining the durations, I have put extra spaces between values to indicate measure separations. Again, this isn't at all necessary, I just find it extremely helpful when debugging your code, figuring out where you have wrong notes or wrong note values, things like that.
Here some examples at around the 9:00 mark.
I'll be adding a pull request in our Github repo to make sure that everyone who wants it has access to this code. If you've come up with some amazing buzzer tunes, I encourage you to do the same. I stopped at three Qwiic Buzzers for my demo, but that doesn't mean that you need to. If anyone wants to tackle, say, Bernstein's Overture to Candide, or Mussorgsky's Pictures at an Exhibition, I would be both excited and terrified to hear that!
Cover image: SparkFun Qwiic Buzzer debuting at the Joan and Sanford I. Weill Recital Hall, Carnagie Hall, NYC. Recital hall image courtesy of Carnagie Hall Organization.
Wonderful electronic program !
You went to all this trouble and didn't include a video/recording of it playing?
Just added in the video above. The examples start around the 9 minute mark. Enjoy!