Skip to content

Instantly share code, notes, and snippets.

@amakukha
Last active July 10, 2019 15:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amakukha/22a7e8254a3982ab1f177a8471ac1a0b to your computer and use it in GitHub Desktop.
Save amakukha/22a7e8254a3982ab1f177a8471ac1a0b to your computer and use it in GitHub Desktop.
Play duo melody with Arduino
/*
* Play duo melody with Arduino
* ============================
*
* Description:
* This sketch simultaneously plays two separate melodies on two (passive)
* speakers or buzzers. This creates effect of a "choir".
* For simplicity, it uses function play2Tones(), which only plays two notes
* of equal duration simultaneosly.
* The actual melody here is the Anthem of Ukraine.
*
* See video of it working (with display added):
* https://youtu.be/0uXolNN-_co
*
* Author: Andriy Makukha (March 2016)
*
* Based on PlayMelody tutorial:
* https://www.arduino.cc/en/Tutorial/PlayMelody
* with some improvements.
*/
// GPIOs ==========================================
/* All you have to do is to connect each of the buzzers to ground and to one of these GPIOs.
* You can change GPIOs as you see fit. */
#define BUZZER1 5
#define BUZZER2 6
// TONES ==========================================
#define NA0 36364
#define NAS0 34323
#define NB0 32396
#define NC1 30578
#define NCS1 28862
#define ND1 27242
#define NDS1 25713
#define NE1 24270
#define NF1 22908
#define NFS1 21622
#define NG1 20408
#define NGS1 19263
#define NA1 18182
#define NAS1 17161
#define NB1 16198
#define NC2 15289
#define NCS2 14431
#define ND2 13621
#define NDS2 12856
#define NE2 12135
#define NF2 11454
#define NFS2 10811
#define NG2 10204
#define NGS2 9631
#define NA2 9091
#define NAS2 8581
#define NB2 8099
#define NC3 7645
#define NCS3 7215
#define ND3 6810
#define NDS3 6428
#define NE3 6067
#define NF3 5727
#define NFS3 5405
#define NG3 5102
#define NGS3 4816
#define NA3 4545
#define NAS3 4290
#define NB3 4050
#define NC4 3822
#define NCS4 3608
#define ND4 3405
#define NDS4 3214
#define NE4 3034
#define NF4 2863
#define NFS4 2703
#define NG4 2551
#define NGS4 2408
#define NA4 2273
#define NAS4 2145
#define NB4 2025
#define NC5 1911
#define NCS5 1804
#define ND5 1703
#define NDS5 1607
#define NE5 1517
#define NF5 1432
#define NFS5 1351
#define NG5 1276
#define NGS5 1204
#define NA5 1136
#define NAS5 1073
#define NB5 1012
#define NC6 956
#define NCS6 902
#define ND6 851
#define NDS6 804
#define NE6 758
#define NF6 716
#define NFS6 676
#define NG6 638
#define NGS6 602
#define NA6 568
#define NAS6 536
#define NB6 506
#define NC7 478
#define NCS7 451
#define ND7 426
#define NDS7 402
#define NE7 379
#define NF7 358
#define NFS7 338
#define NG7 319
#define NGS7 301
#define NA7 284
#define NAS7 268
#define NB7 253
#define NC8 239
#define NCS8 225
#define ND8 213
#define NDS8 201
// Define a special note, 'R', to represent a rest
#define REST 0
#define REST_COUNT 185
#define TEMPO 35000
#define PAUSE 1000 // length of pause between notes
// MELODY and TIMING =======================================
// notes in the melody 1
int melody1[] = {
ND4, ND4, ND4, NC4, ND4, NDS4,
NF4, NDS4, ND4, NC4,
NAS3, ND4, NA3, ND4,
NG3, NA3, NAS3, NC4,
// Repeat
ND4, ND4, ND4, NC4, ND4, NDS4,
NF4, NDS4, ND4, NC4,
NAS3, ND4, NA3, ND4,
NG3, NG3, REST,
// Third row
NA3, NA3, ND4, NC4, NAS3, NA3,
NG3, NA3, NAS3, NG3, NA3, NA3,
NAS3, NAS3, NC4, NC4,
ND4, ND4, REST,
// Repeat
NA3, NA3, ND4, NC4, NAS3, NA3,
NG3, NA3, NAS3, NG3, NA3, NA3,
NAS3, ND4, NA3, ND4, // Slight change
NG3, NA3, NAS3, NC4, ND4, NDS4, // Change
// Fifth row
NF4, NE4, NF4, ND4,
NC4, NC4, NF4, NDS4, ND4, NC4,
NAS3, NAS3, NC4, NC4,
ND4, NC4, ND4, NDS4,
// Repeat
NF4, NE4, NF4, ND4,
NC4, NC4, NF4, NDS4, ND4, NC4,
NAS3, ND4, NA3, ND4,
NG3, NG3, REST
};
// note durations: 1 = 1/16 note, 3 = 3/16 note, etc.:
int beats1[] = {
6, 2, 2, 2, 2, 2,
6, 2, 4, 4,
4, 4, 4, 4,
6, 2, 4, 4,
// Repeat
6, 2, 2, 2, 2, 2,
6, 2, 4, 4,
4, 4, 4, 4,
8, 4, 4, // slight change
// Third row
4, 4, 2, 2, 2, 2,
2, 2, 2, 2, 4, 4,
4, 4, 4, 4,
8, 4, 4,
// Repeat
4, 4, 2, 2, 2, 2,
2, 2, 2, 2, 4, 4,
4, 4, 4, 4,
6, 2, 2, 2, 2, 2,
// Fifth row
6, 2, 4, 4,
4, 4, 2, 2, 2, 2,
4, 4, 4, 4,
6, 2, 4, 4,
// Repeat
6, 2, 4, 4,
4, 4, 2, 2, 2, 2,
4, 4, 4, 4,
8, 4, 4
};
// notes in the melody 2
int melody2[] = {
NAS3, NAS3, NAS3, NA3, NAS3, NC4,
ND4, NC4, NAS3, NA3,
NG3, NAS3, NA3, NFS3,
NG3, NFS3, NG3, NF3,
// Repeat
NAS3, NAS3, NAS3, NA3, NAS3, NC4,
ND4, NC4, NAS3, NA3,
NG3, NAS3, NA3, NFS3,
NG3, NG3, REST,
// Third row
NFS3, NFS3, NFS3, NA3, NG3, NFS3,
NG3, NG3, NG3, NG3, NFS3, NFS3,
NG3, NG3, NF3, NF3,
NAS3, NAS3, REST,
// Repeat
NFS3, NFS3, NFS3, NA3, NG3, NFS3,
NG3, NG3, NG3, NG3, NFS3, NFS3,
NG3, NG3, NFS3, NFS3, // Slight change
NG3, NFS3, NG3, NA3, NAS3, NC4, // Change
// Fifth row
ND4, NCS4, ND4, NAS3,
NA3, NA3, NA3, NC4, NAS3, NA3,
NG3, NG3, NA3, NF3,
NAS3, NA3, NAS3, NC4,
// Repeat
ND4, NCS4, ND4, NAS3,
NA3, NA3, NA3, NC4, NAS3, NA3,
NG3, NG3, NFS3, NFS3,
NG3, NG3, REST
};
void setup() {
pinMode(BUZZER1, OUTPUT);
pinMode(BUZZER2, OUTPUT);
//playTone(NE4, 32*TEMPO*5);
//delay(1000);
if(sizeof(melody1)!=sizeof(melody2) || sizeof(melody1)!=sizeof(beats1)) {
playTone(NE4, 32*TEMPO);
playTone(REST, 16*TEMPO);
playTone(NE4, 16*TEMPO);
return;
}
int n = sizeof(beats1) / 2;
for (int i=0; i<n; i++) {
play2Tones(melody1[i], melody2[i], beats1[i] * 4 * TEMPO);
}
}
void rest(long duration) {
for (int j = 0; j < REST_COUNT; j++) {
delayMicroseconds(duration);
}
}
void playTone(long tone_, long duration) {
byte state=LOW;
long elapsed_time = 0;
if (tone_ > 0) {
tone_ >>= 1;
while (elapsed_time < duration) {
state = state==HIGH ? LOW : HIGH;
digitalWrite(BUZZER1,state);
delayMicroseconds(tone_);
elapsed_time += tone_;
}
}
else rest(duration);
}
void play2Tones(long tone1, long tone2, long duration) {
byte s1, s2; // state of the buzzers
long sum1, sum2, cur, next, n1, n2;
cur = next = sum1 = sum2 = 0;
// Init buzzers
s1 = s2 = LOW;
digitalWrite(BUZZER1, s1);
digitalWrite(BUZZER2, s2);
if (tone1 > 0 && tone2 > 0) {
duration -= PAUSE;
tone1 >>= 1; tone2 >>= 1;
while (cur < duration) {
next = min(min(sum1 + tone1, sum2 + tone2), duration);
delayMicroseconds(next-cur);
if(sum1 + tone1 == next) {
s1 = s1==HIGH ? LOW : HIGH;
digitalWrite(BUZZER1, s1);
sum1 += tone1;
}
if(sum2 + tone2 == next) {
s2 = s2==HIGH ? LOW : HIGH;
digitalWrite(BUZZER2, s2);
sum2 += tone2;
}
cur = next;
}
delayMicroseconds(PAUSE);
}
else if (tone1 > 0 || tone2 > 0) {
// TODO: choose appropriate buzzer
playTone(tone1 > 0 ? tone1 : tone2, duration);
}
else rest(duration);
}
void loop() {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment