Skip to content

Instantly share code, notes, and snippets.

@noobermin
Created December 24, 2020 18:26
Show Gist options
  • Save noobermin/0c498266593c759fd82259b6a395c2e1 to your computer and use it in GitHub Desktop.
Save noobermin/0c498266593c759fd82259b6a395c2e1 to your computer and use it in GitHub Desktop.
/*
* 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, &timest);
//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);
}
@Souravgoswami
Copy link

Really great gist!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment