Last active
July 10, 2019 15:35
-
-
Save amakukha/22a7e8254a3982ab1f177a8471ac1a0b to your computer and use it in GitHub Desktop.
Play duo melody with Arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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