Created
December 24, 2020 18:26
-
-
Save noobermin/0c498266593c759fd82259b6a395c2e1 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
/* | |
* Animal Crossing Toy Day on an Arduino, by noobermin (or awindywalker) | |
* | |
* Everything except the transcription of the song is in the public domain. | |
*/ | |
// The tone library conflicts with the Arduino core `tone` and `noTone` routines! They | |
// register the similar ISR's leading to a conflict. It is needed though as `tone` doesn't work | |
// with more than one buzzer (port). | |
// What I did to make it work is I deleted the file in a clean copy of the arduino IDE, commented | |
// out the declarations in Arduino.h, and then installed the tone library using the IDE. | |
#include <Tone.h> | |
// | |
// circuit definitions (pins) | |
// | |
// light pins (4, hopefully next to each other in a line on a breadboard) | |
#define LIGHT0 8 | |
#define LIGHT1 9 | |
#define LIGHT2 10 | |
#define LIGHT3 11 | |
// pins for buzzers (2) | |
#define BUZZERA 3 | |
#define BUZZERC 5 | |
// all in octave 4 | |
// shout out to Brett Hagman and Tom Igoe for their example on arduino.cc | |
// see https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody | |
#define _C_4 262 | |
#define _Cs4 277 | |
#define _D_4 294 | |
#define _Ds4 311 | |
#define _E_4 330 | |
#define _F_4 349 | |
#define _Fs4 370 | |
#define _G_4 392 | |
#define _Gs4 415 | |
#define _A_4 440 | |
#define _As4 466 | |
#define _B_4 494 | |
#define _R_ 0 | |
#define _C_ 1 | |
#define _Cs 2 | |
#define _D_ 3 | |
#define _Ds 4 | |
#define _E_ 5 | |
#define _F_ 6 | |
#define _Fs 7 | |
#define _G_ 8 | |
#define _Gs 9 | |
#define _A_ 10 | |
#define _As 11 | |
#define _B_ 12 | |
#define _Ab _GS | |
#define _Bb _AS | |
#define _Db _CS | |
#define _Eb _DS | |
#define _Gb _Fs | |
// time for each beat in milliseconds | |
//#define BASETIME 75 //75 sounds better for me but changed it | |
//to 60 so it can fit better in an online video | |
#define BASETIME 60 | |
// 75*32*4 for testing bars | |
//#define SONG_DURATION 9600 | |
// 75*32*32 | |
//#define SONG_DURATION 76800 | |
// 60*32*32 | |
#define SONG_DURATION 61440 | |
struct note_t{ | |
note_t (short _note=_C_, char _octave=4, char _duration=200) : | |
note( (_note << 3) | ((_octave-1)&07) ), duration(_duration){} | |
note_t (char _note, char _duration=200) : | |
note(_note), duration(_duration){} | |
char note; | |
char duration; | |
operator==(const note_t& in) const { | |
return note == in.note && duration == in.duration; | |
} | |
}; | |
const note_t SONG_END(_R_,0,1); | |
short note_freq(const note_t& in){ | |
char octave = (in.note & 07) + 1; | |
char note = in.note >> 3; | |
if (note == 0) return 0; | |
switch(octave) { | |
case 1: | |
switch (note) { | |
case _C_: return 33; | |
case _Cs: return 35; | |
case _D_: return 37; | |
case _Ds: return 39; | |
case _E_: return 41; | |
case _F_: return 44; | |
case _Fs: return 46; | |
case _G_: return 49; | |
case _Gs: return 52; | |
case _A_: return 55; | |
case _As: return 58; | |
case _B_: return 62; | |
} | |
case 2: | |
switch (note) { | |
case _C_: return 65; | |
case _Cs: return 69; //nic...eh w/e | |
case _D_: return 73; | |
case _Ds: return 78; | |
case _E_: return 82; | |
case _F_: return 87; | |
case _Fs: return 93; | |
case _G_: return 98; | |
case _Gs: return 104; | |
case _A_: return 110; | |
case _As: return 117; | |
case _B_: return 123; | |
} | |
case 3: | |
switch (note) { | |
case _C_: return 131; | |
case _Cs: return 139; | |
case _D_: return 147; | |
case _Ds: return 156; | |
case _E_: return 165; | |
case _F_: return 175; | |
case _Fs: return 185; | |
case _G_: return 196; | |
case _Gs: return 208; | |
case _A_: return 220; | |
case _As: return 233; | |
case _B_: return 247; | |
} | |
case 4: | |
switch(note) { | |
case _C_: return 262; | |
case _Cs: return 277; | |
case _D_: return 294; | |
case _Ds: return 311; | |
case _E_: return 330; | |
case _F_: return 349; | |
case _Fs: return 370; | |
case _G_: return 392; | |
case _Gs: return 415; | |
case _A_: return 440; | |
case _As: return 466; | |
case _B_: return 494; | |
} | |
case 5: | |
switch(note){ | |
case _C_: return 523; | |
case _Cs: return 554; | |
case _D_: return 587; | |
case _Ds: return 622; | |
case _E_: return 659; | |
case _F_: return 698; | |
case _Fs: return 740; | |
case _G_: return 784; | |
case _Gs: return 831; | |
case _A_: return 880; | |
case _As: return 932; | |
case _B_: return 988; | |
} | |
case 6: | |
switch(note){ | |
case _C_: return 1047; | |
case _Cs: return 1109; | |
case _D_: return 1175; | |
case _Ds: return 1245; | |
case _E_: return 1319; | |
case _F_: return 1397; | |
case _Fs: return 1480; | |
case _G_: return 1568; | |
case _Gs: return 1661; | |
case _A_: return 1760; | |
case _As: return 1865; | |
case _B_: return 1976; | |
} | |
case 7: | |
switch(note){ | |
case _C_: return 2093; | |
case _Cs: return 2217; | |
case _D_: return 2349; | |
case _Ds: return 2489; | |
case _E_: return 2637; | |
case _F_: return 2794; | |
case _Fs: return 2960; | |
case _G_: return 3136; | |
case _Gs: return 3322; | |
case _A_: return 3520; | |
case _As: return 3729; | |
case _B_: return 3951; | |
} | |
case 8: | |
switch(note){ | |
case _C_: return 4186; | |
case _Cs: return 4435; | |
case _D_: return 4699; | |
case _Ds: return 4978; | |
default: return 0; | |
} | |
} | |
} | |
int get_curnote(const note_t* song, long timenow, long* timeacc, long* timest) { | |
long _timest=0, _timeacc=0; | |
int notei=0; | |
for (;;++notei) { | |
_timest = _timeacc; | |
_timeacc += (long)song[notei].duration*BASETIME; | |
if (timenow < _timeacc) break; | |
} | |
if (timeacc) *timeacc =_timeacc; | |
if (timest) *timest =_timest; | |
return notei; | |
} | |
Tone tracka,trackc; | |
void play_track_tone(const Tone& track,const note_t* song,long timenow, int pause=BASETIME){ | |
long timeacc = 0, timest = 0; | |
int notei = get_curnote(song, timenow, &timeacc, ×t); | |
//timing | |
const short freq = note_freq(song[notei]); | |
if ( (timenow - timest) < (song[notei].duration*BASETIME - pause) && freq > 0) { | |
track.play(freq); | |
} else { | |
track.stop(); | |
} | |
} | |
void lightup(const note_t* song, long timenow){ | |
int i = get_curnote(song, timenow, NULL, NULL); | |
uint8_t cur = song[i].note; | |
digitalWrite(LIGHT0, cur & 01); | |
digitalWrite(LIGHT1, cur & 02); | |
digitalWrite(LIGHT2, cur & 04); | |
digitalWrite(LIGHT3, cur & 010); | |
} | |
// song tracks | |
// based on a score by "erikheinicke" on musescore.com, original composed by Manaka Kataoka and Atsuko Asahi | |
// link as of Dec 24, 2020: https://musescore.com/user/8425261/scores/5059404 | |
// I claim no rights to these scores, despite some edits to make it sound better on two buzzers, use of this is strictly for | |
// academic purposes, and the original copyright of Animal Crossing and the music lie with the original copyright holders. | |
// So I or you don't get in trouble, only use these parts for educational purposes. | |
#define N(n,o,d) note_t(n,o,d) | |
const note_t song_toydayc[] = { | |
N(_Gs, 3, 4), N(_R_, 4, 20), N(_Cs, 4, 8), | |
N(_C_, 4, 8), N(_R_, 3, 4), N(_G_, 3, 4), N(_Ds, 4, 8), N(_Cs, 4, 8), | |
N(_Gs, 3, 8), N(_Ds, 5, 4), N(_R_, 4, 4), N(_C_, 5, 4), N(_R_, 4, 4), N(_Cs, 5, 4), N(_R_, 4, 4), | |
N(_Ds, 5, 16), N(_Ds, 4, 16), | |
// | |
N(_Gs,5,8), N(_G_,5,4), N(_F_,5,4), N(_Ds,5,12), N(_C_,5,2), N(_Cs,5,2), | |
N(_Ds,5,8), N(_Ds,5,4), N(_F_,5,4), N(_Cs,5, 1), N(_Ds,5,1), N(_Cs,5,2),N(_C_,5,4), N(_Cs,5,4), N(_Ds,5,4), | |
N(_C_,5,8), N(_R_,3,24), | |
N(_R_,4,8), N(_C_,4,8), N(_Cs,4,8), N(_G_,4,8), | |
// | |
N(_Gs,4,8), N(_G_,4,4), N(_F_,4,4), N(_Ds,4,12), N(_C_,4,2), N(_Cs,4,2), | |
N(_Ds,4,8), N(_Ds,4,4), N(_F_,4,4), N(_Cs,4, 1), N(_Ds,4,1), N(_Cs,4,2),N(_C_,4,4), N(_Cs,4,4), N(_Ds,4,4), | |
N(_C_,4,8), N(_G_,5,4), N(_Gs,4,4), N(_Ds,4, 4), N(_Gs,4,4), N(_As,4,4),N(_Gs,4,4), | |
N(_Ds,4,8), N(_R_,4,4), N(_Ds,4,4), N(_Gs,5, 8), N(_Ds,5,4), N(_Cs,5,4), | |
// | |
N(_C_,6,8), N(_As,5,4), N(_Gs,5,4), N(_Ds,5,8), N(_C_,5,8), | |
N(_Ds,5,12),N(_Cs,5,4), N(_C_,5,8), N(_As,4,8), | |
N(_C_,5,8), N(_Gs,5,16),N(_Gs,5,4),N(_G_,5,4), | |
N(_Ds,6,8), N(_R_,4,24), | |
// | |
N(_Ds,4,8), N(_G_,4,8), N(_Gs,4,16), | |
N(_As,4,8), N(_Gs,4,4), N(_G_,4, 4), N(_Gs,4,8), N(_G_,4, 4),N(_F_,4, 4), | |
N(_Ds,4,8), N(_G_,5,8), N(_Gs,5,8), N(_G_,5,4), N(_Gs,5,4), | |
N(_As,5,8), N(_Gs,5,4), N(_G_,5,4), N(_Gs,5,16), | |
// | |
N(_Ds, 5, 8), N(_G_, 5, 8), N(_Gs, 5, 8), N(_G_, 5, 4), N(_Gs, 5, 4), | |
N(_As, 5, 6), N(_C_, 6, 1), N(_As, 5, 1), N(_Gs, 5, 4), N(_G_, 5, 4), N(_Gs, 5, 6), N(_As, 5, 1), N(_Gs, 5, 1), N(_G_, 5, 4), N(_F_, 5, 4), | |
N(_Ds, 5, 24), N(_R_, 4, 8), | |
N(_Ds, 5, 8), N(_R_, 4, 24), | |
// | |
N(_G_, 4, 4), N(_R_, 4, 28), | |
N(_As, 4, 4), N(_R_, 4, 28), | |
N(_G_, 4, 4), N(_R_, 4, 28), | |
N(_As, 4, 4), N(_R_, 4, 12), N(_D_, 6, 2),N(_R_, 4, 2),N(_C_, 6, 2),N(_R_, 4, 2),N(_As, 5, 2),N(_R_, 4, 2),N(_Gs, 5, 2),N(_R_, 4, 2), | |
// | |
N(_G_, 5, 8), N(_F_, 5, 4), N(_Ds, 5, 4), N(_As, 4, 8), N(_G_, 4, 4), N(_Gs, 4, 4), | |
N(_As, 4, 8), N(_As, 4, 4), N(_C_, 5, 4), N(_Gs, 4, 4), N(_G_, 4, 4), N(_Gs, 4, 4), N(_As, 4, 4), | |
N(_Gs, 4, 16), N(_G_, 4, 16), | |
N(_F_, 6, 8), N(_D_, 6, 8), N(_R_, 4, 16), | |
SONG_END | |
}; | |
const note_t song_toydaya[] = { | |
N(_Gs, 2, 4), N(_R_, 3, 4), N(_Ds, 4, 4), N(_Ds, 3, 4), N(_Ds, 3, 8), N(_Ds,3,8), | |
N(_Ds, 3, 4), N(_Gs, 2, 4), N(_Ds, 3, 4), N(_Gs, 2, 4), N(_R_, 3, 4), N(_Gs, 2, 4), N(_Ds, 3, 8), | |
N(_Gs, 2, 8), N(_Ds, 4, 4), N(_Ds, 3, 4), N(_Ds, 3, 8), N(_Ds,3,8), | |
N(_C_, 4, 4), N(_Gs, 2, 4), N(_Ds, 3, 4), N(_Ds, 3, 4), N(_Gs, 3, 4), N(_Gs, 2, 4), N(_As, 3, 8), | |
// | |
N(_Gs, 2, 8), N(_R_, 3, 4), N(_Ds, 3, 4), N(_Ds, 3, 8), N(_G_, 3, 8), | |
N(_C_, 3, 8), N(_R_, 3, 4), N(_G_, 3, 4), N(_Gs, 3, 8), N(_As, 3, 8), | |
N(_Gs, 3, 8), N(_G_, 4, 4), N(_Ds, 3, 4), N(_Ds, 3, 8), N(_As, 3, 8), | |
N(_C_, 4, 4), N(_Gs, 2, 4), N(_Ds, 3, 4), N(_Ds, 3, 4), N(_Gs, 3, 4), N(_Gs, 2, 4), N(_As, 3, 8), | |
// | |
N(_Gs, 2, 8), N(_R_, 3, 4), N(_Ds, 3, 4), N(_Ds, 3, 8), N(_G_, 3, 8), | |
N(_C_, 3, 8), N(_R_, 3, 4), N(_G_, 3, 4), N(_Gs, 3, 8), N(_As, 3, 8), | |
N(_Gs, 3, 8), N(_R_, 4, 4), N(_Ds, 3, 4), N(_Ds, 3, 8), N(_As, 3, 8), | |
N(_Ds, 3, 8), N(_R_, 4, 4), N(_Ds, 4, 4), N(_Ds, 4, 16), | |
// | |
N(_Gs, 2, 4), N(_G_, 3, 4), N(_C_, 4, 8), N(_As, 2, 4), N(_Gs, 3, 4), N(_Cs, 4, 8), | |
N(_C_, 3, 4), N(_Gs, 3, 4), N(_Ds, 4, 8), N(_As, 2, 4), N(_Gs, 3, 4), N(_Cs, 4, 8), | |
N(_Ds, 3, 4), N(_Gs, 3, 4), N(_C_, 4, 8), N(_As, 2, 4), N(_Gs, 3, 4), N(_Cs, 4, 8), | |
N(_C_, 3, 4), N(_Gs, 3, 4), N(_Ds, 4, 8), N(_Cs, 3, 4), N(_Gs, 3, 4), N(_Cs, 4, 4), N(_F_, 4, 4), | |
// | |
N(_F_, 3, 4), N(_Gs, 3, 4), N(_C_, 4, 8), N(_Ds, 3, 4), N(_Gs, 3, 4), N(_Cs, 4, 8), | |
N(_Cs, 3, 4), N(_As, 3, 4), N(_Ds, 4, 8), N(_Ds, 3, 4), N(_Gs, 3, 4), N(_Cs, 4, 8), | |
N(_Cs, 3, 4), N(_Gs, 3, 4), N(_Ds, 4, 4), N(_Gs, 4, 4), N(_Ds, 3, 4), N(_Gs, 3, 4), N(_F_, 4, 4), N(_Gs, 3, 4), | |
N(_F_, 3, 4), N(_Gs, 3, 4), N(_Ds, 4, 4), N(_Gs, 3, 4), N(_Ds, 3, 8), N(_C_, 4, 8), | |
// | |
N(_Ds, 3, 8), N(_F_, 3, 8), N(_Gs, 3, 8), N(_F_, 3, 4), N(_Gs, 3, 4), | |
N(_As, 3, 6), N(_C_, 4, 1), N(_As, 3, 1), N(_Gs, 3, 4), N(_G_, 3, 4), N(_Gs, 3, 6), N(_As, 3, 1), N(_Gs, 3, 1), N(_G_, 3, 4), N(_F_, 3, 4), | |
N(_Ds, 3, 4), N(_Gs, 3, 4), N(_Ds, 4, 4), N(_Gs, 3, 4), N(_Ds, 3, 4), N(_G_, 3, 4), N(_Cs, 4, 4), N(_G_, 3, 4), | |
N(_Ds, 3, 4), N(_F_, 3, 4), N(_Ds, 4, 4), N(_F_, 3, 4), N(_Ds, 3, 4), N(_R_, 4,12), | |
// | |
N(_R_, 4, 16), N(_As, 3, 4), N(_R_, 3, 12), | |
N(_R_, 4, 16), N(_Ds, 3, 4), N(_R_, 3, 12), | |
N(_R_, 4, 16), N(_As, 3, 4), N(_R_, 3, 12), | |
N(_R_, 4, 16), N(_R_, 4, 16), | |
// | |
N(_Gs, 3, 4), N(_As, 3, 4), N(_D_, 4, 4), N(_F_, 4, 4), N(_D_, 4, 4), N(_C_, 4, 4), N(_As, 3, 8), | |
N(_G_, 3, 4), N(_As, 3, 4), N(_Ds, 4, 4), N(_F_, 4, 4), N(_Gs, 4, 8), N(_R_, 4, 8), | |
N(_F_, 3, 4), N(_Gs, 3, 4), N(_Ds, 4, 4), N(_F_, 4, 4), N(_R_, 4, 16), | |
N(_As, 4, 16), N(_R_, 4, 12),N(_G_, 3, 4), | |
SONG_END | |
}; | |
// end of music scores | |
#undef N | |
//light show | |
#define F(a,d) note_t((char)a,d) | |
const note_t lights_toydayl[] = { | |
F(0x1, 8), F(0x8, 4), F(0xa, 4), F(0x5, 8), F(0x8, 8), | |
F(0x4, 8), F(0x2, 4), F(0xa, 4), F(0x9, 8), F(0x6, 8), | |
F(0x1, 8), F(0x2, 8), F(0x4, 8), F(0x8, 8), | |
F(0xc, 16), F(0x3, 16), | |
// | |
F(0x8, 8), F(0x4, 4), F(0x2, 4), F(0x1,10), F(0x0, 2), F(0x1, 2), F(0x2, 2), | |
F(0x4, 6), F(0x0, 2), F(0x4, 4), F(0x8, 4), F(0x4, 1), F(0x2, 1), F(0x4, 2), F(0x1, 4), F(0x2, 4), F(0x4, 4), | |
F(0x1,32), | |
F(0x0, 8), F(0x3, 8), F(0x6, 8), F(0xc, 6), F(0x0,2), | |
// | |
F(0x0c, 8), F(0x06, 4), F(0x03, 4), F(0x09,10), F(0x00, 2), F(0x03, 2), F(0x06, 2), | |
F(0x0c, 6), F(0x00, 2), F(0x0c, 4), F(0x09, 4), F(0x0c, 1), F(0x03, 1), F(0x0c, 2), F(0x03, 4), F(0x06, 4), F(0x09, 4), | |
F(0x01,16), F(0x05, 8), F(0x0a, 8), | |
F(0x05, 8), F(0x01, 4), F(0x00, 4), F(0x08, 8), F(0x04, 4), F(0x02, 4), | |
// | |
F(0x01, 4), F(0x02, 4), F(0x04, 8), F(0x01, 4), F(0x02, 4), F(0x04, 8), | |
F(0x08, 4), F(0x04, 4), F(0x02, 8), F(0x08, 4), F(0x04, 4), F(0x02, 8), | |
F(0x01, 4), F(0x02, 4), F(0x04, 8), F(0x08, 2), F(0x04, 4), F(0x02, 8), | |
F(0x01, 4), F(0x02, 4), F(0x04, 8), F(0x01, 4), F(0x02, 4), F(0x04, 4), F(0x08, 2), F(0x04, 2), | |
// | |
F(0x0e,16), F(0x07,16), | |
F(0x0d,16), F(0x0b,16), | |
F(0x0e, 4), F(0x0d, 4), F(0x0b, 4), F(0x0d, 4), F(0x0e, 4), F(0x0d, 4), F(0x0b, 4), F(0x07, 4), | |
F(0x0b, 4), F(0x0d, 4), F(0x0b, 4), F(0x07, 4), F(0x0f, 16), | |
// | |
F(0xe,16), F(0x7, 8), F(0xd, 4), F(0xb, 4), | |
F(0x9, 6), F(0x6, 1), F(0x9, 1), F(0x6, 4), F(0x9, 4), F(0xa, 6), F(0x5, 1), F(0xa, 1), F(0x5, 4), F(0xa, 4), | |
F(0x1,16), F(0x2,16), | |
F(0x8,16), F(0x4, 2), F(0x0,14), | |
// | |
F(0x01, 4), F(0x0e, 12), F(0x0c, 4), F(0x00, 12), | |
F(0x08, 4), F(0x0e, 12), F(0x03, 4), F(0x00, 12), | |
F(0x01, 4), F(0x0e, 12), F(0x0c, 4), F(0x00, 12), | |
F(0x08, 2), F(0x00, 14), F(0x08, 2), F(0x00, 2), F(0x04, 2), F(0x00, 2), F(0x02, 2), F(0x0, 2), F(0x1, 2), F(0x0, 2), | |
// | |
F(0x8, 8), F(0x4, 4), F(0x2, 4), F(0x1, 6),F(0x0, 2), F(0x1, 4), F(0x2, 4), | |
F(0xb, 6), F(0xf, 2), F(0xe, 4), F(0xd, 4), F(0xb,8), F(0x6, 8), | |
F(0x4,14), F(0x0, 2), F(0x2, 8), F(0x0, 8), | |
F(0x8, 2), F(0x0, 6), F(0x6, 2), F(0x0,18), F(0x2, 2), F(0x0, 4), | |
SONG_END | |
}; | |
#undef F | |
void setup() { | |
tracka.begin(BUZZERA); | |
trackc.begin(BUZZERC); | |
pinMode(LIGHT0, OUTPUT); | |
pinMode(LIGHT1, OUTPUT); | |
pinMode(LIGHT2, OUTPUT); | |
pinMode(LIGHT3, OUTPUT); | |
} | |
void loop() { | |
long now = millis() % SONG_DURATION; | |
play_track_tone(tracka,song_toydaya, now, BASETIME/3); | |
play_track_tone(trackc,song_toydayc, now, BASETIME/3); | |
lightup(lights_toydayl, now); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Really great gist!