From c4aafd1d9bc9d410a334a300712415ec8cd03c1b Mon Sep 17 00:00:00 2001 From: Andrew Lalis Date: Sun, 27 Nov 2022 14:41:49 +0100 Subject: [PATCH] Added source. --- light.h | 107 +++++++++++++++++++++++++++ music.h | 156 +++++++++++++++++++++++++++++++++++++++ nightlight.ino | 121 ++++++++++++++++++++++++++++++ pitches.h | 90 +++++++++++++++++++++++ songs.h | 195 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 669 insertions(+) create mode 100644 light.h create mode 100644 music.h create mode 100644 nightlight.ino create mode 100644 pitches.h create mode 100644 songs.h diff --git a/light.h b/light.h new file mode 100644 index 0000000..e29b284 --- /dev/null +++ b/light.h @@ -0,0 +1,107 @@ +#define LC_PERIOD 60000 +#define LC_FREQ 1.0 / LC_PERIOD + +struct Color { + float r, g, b; +}; + +#define COLOR_RED {1, 0, 0} +#define COLOR_GREEN {0, 1, 0} +#define COLOR_BLUE {0, 0, 1} +#define COLOR_ORANGE {1, 0.3, 0} +#define COLOR_YELLOW {1, 1, 0} +#define COLOR_PURPLE {0.4, 0, 1} + +Color lc_multiplyColor(Color c, float x) { + return {c.r * x, c.g * x, c.b * x}; +} + +Color lc_interpolateColor(Color c1, Color c2, float x) { + Color c; + c.r = (1 - x) * c1.r + x * c2.r; + c.g = (1 - x) * c1.g + x * c2.g; + c.b = (1 - x) * c1.b + x * c2.b; + return c; +} + + +typedef Color (*lc_timeFunction)(unsigned int); + +// Simple sin function with the same period as the standard LC_PERIOD. +Color lc_tf_greenLight(unsigned int elapsed_ms) { + double x = pow(sin(PI * LC_FREQ * 10 * elapsed_ms), 2); + return {0, x, 0}; +} + +// Fast sin function. +Color lc_tf_SinFast(unsigned int elapsed_ms) { + double x = (sin(2 * PI * LC_FREQ * 100 * elapsed_ms) + 1) / 2; + return {0, x, 0}; +} + +// Helper function for color-pulsing time functions. +Color lc_colorPulsar(unsigned int elapsed_ms, Color* colors, unsigned int count) { + const unsigned int colorPeriod = LC_PERIOD / count; + double x = (sin(2 * PI * LC_FREQ * count * elapsed_ms - PI / 2) + 1) / 2; + for (unsigned int i = 1; i <= count; i++) { + if (elapsed_ms < colorPeriod * i) { + return lc_multiplyColor(colors[i - 1], x); + } + } + return lc_multiplyColor({1, 1, 1}, x); +} + +// Red, Green, then Blue pulse. +Color lc_tf_rgbPulse(unsigned int elapsed_ms) { + const Color colors[3]; + colors[0] = COLOR_RED; + colors[1] = COLOR_GREEN; + colors[2] = COLOR_BLUE; + return lc_colorPulsar(elapsed_ms, colors, 3); +} + +// Rainbow color function. +Color lc_tf_rainbowPulse(unsigned int elapsed_ms) { + const Color colors[6]; + colors[0] = COLOR_RED; + colors[1] = COLOR_ORANGE; + colors[2] = COLOR_YELLOW; + colors[3] = COLOR_GREEN; + colors[4] = COLOR_BLUE; + colors[5] = COLOR_PURPLE; + return lc_colorPulsar(elapsed_ms, colors, 6); +} + +Color lc_tf_yellowGreen(unsigned int elapsed_ms) { + const Color colors[2]; + colors[0] = COLOR_YELLOW; + colors[1] = COLOR_GREEN; + return lc_colorPulsar(elapsed_ms, colors, 2); +} + +// Flame +Color lc_tf_flame(unsigned int elapsed_ms) { + float colorValue = (sin(2 * PI * LC_FREQ * 10 * elapsed_ms) + 1) / 2; + float flameCoefficients[] = { + 0.1, 0.35, 0.04, 0.75, 0.92, 0.55, 0.4, 0.22, 0.64, 0.85 + }; + const unsigned int fc_count = 10; + float flameIntensity = 0; + for (int i = 0; i < fc_count; i++) { + flameIntensity += (sin(2 * flameCoefficients[i] * elapsed_ms) + 1) / 2; + } + flameIntensity /= fc_count; + Color flame = lc_interpolateColor({1.0, 0.025, 0}, {1.0, 0.1, 0}, colorValue); + return lc_multiplyColor(flame, flameIntensity); +} + +lc_timeFunction LC_TIME_FUNCTIONS[] = { + &lc_tf_flame, + &lc_tf_greenLight, + &lc_tf_yellowGreen, + &lc_tf_SinFast, + &lc_tf_rgbPulse, + &lc_tf_rainbowPulse +}; + +#define LC_TIME_FUNCTION_COUNT 6 diff --git a/music.h b/music.h new file mode 100644 index 0000000..7b9f904 --- /dev/null +++ b/music.h @@ -0,0 +1,156 @@ +#ifndef __MUSIC_H__ +#define __MUSIC_H__ + +#include +#include + +#include "pitches.h" + +struct Note { + unsigned short frequency; + float duration; +}; + +struct Song { + unsigned short tempo; // Notes per minute to play. + unsigned int size; // The number of notes. + struct Note* notes; // The notes data. + unsigned short maxFreq; + unsigned short minFreq; +}; + +struct PlayingSong { + bool playing; + unsigned int elapsed_ms; + unsigned int next_note_at; + size_t current_note; + struct Song song; +}; + +struct Note makeNote(unsigned short f, float t) { + struct Note n; + n.frequency = f; + n.duration = t; + return n; +} + +struct Song makeSong(unsigned short tempo, unsigned int size, struct Note* notes) { + struct Song s; + s.tempo = tempo; + s.size = size; + s.notes = notes; + s.maxFreq = notes[0].frequency; + s.minFreq = notes[0].frequency; + for (unsigned int i = 1; i < size; i++) { + unsigned short f = notes[i].frequency; + if (f != NOTE_REST && f > s.maxFreq) s.maxFreq = f; + if (f != NOTE_REST && f < s.minFreq) s.minFreq = f; + } + return s; +} + +void playSong(struct PlayingSong* ps, struct Song s) { + ps->playing = true; + ps->elapsed_ms = 0; + ps->current_note = 0; + ps->next_note_at = 0; + ps->song = s; +} + +unsigned int getMillisecondsPerNote(struct Song s) { + return 240000 / s.tempo; +} + +unsigned int getNoteDuration(struct Song s, size_t note) { + return getMillisecondsPerNote(s) / s.notes[note].duration; +} + +unsigned int getSongDuration(struct Song s) { + return getMillisecondsPerNote(s) * s.size; +} + +float getCurrentNoteProgress(struct PlayingSong ps) { + unsigned int timeLeft = ps.next_note_at - ps.elapsed_ms; + return getNoteDuration(ps.song, ps.current_note) - timeLeft; +} + +float getRelativeNoteIntensity(struct Note n, struct Song s) { + float min2 = sqrt(s.minFreq); + float max2 = sqrt(s.maxFreq); + float f2 = sqrt(n.frequency); + + //float f = ((float) n.frequency - s.minFreq) / (s.maxFreq - s.minFreq); + float f = (f2 - min2) / (max2 - min2); + if (f < 0) return 0; + if (f > 1) return 1; + return f; +} + +// Updates the given playing song, and returns a reference to a note to play, if any. Otherwise, nullptr is returned. +struct Note* updateSong(struct PlayingSong* ps, unsigned int elapsed_ms) { + if (!ps->playing) return NULL; + ps->elapsed_ms += elapsed_ms; + struct Note* note_to_play = NULL; + if (ps->elapsed_ms > ps->next_note_at) { + ps->current_note++; + if (ps->current_note < ps->song.size) { + note_to_play = &ps->song.notes[ps->current_note]; + ps->next_note_at = ps->elapsed_ms + (getMillisecondsPerNote(ps->song) / note_to_play->duration); + } else { + ps->playing = false; + } + } + return note_to_play; +} + +float getInterpolatedRelativeIntensity(struct PlayingSong* ps) { + //return getRelativeNoteIntensity(ps->song.notes[ps->current_note], ps->song); + // TODO: Figure out cubic bezier interpolation. + struct Note note_a; + struct Note note_b; + float dur_a; + float dur_b; + unsigned int elapsed_time; // Elapsed ms between note a and b. + unsigned int time_until_next_note = ps->next_note_at - ps->elapsed_ms; + unsigned int current_note_dur = getNoteDuration(ps->song, ps->current_note); + unsigned int current_note_elapsed_time = (current_note_dur - time_until_next_note); + if (current_note_elapsed_time < current_note_dur / 2) { + // We are on the lower-half of the current note. + if (ps->current_note == 0) { + note_a = makeNote(ps->song.minFreq, 4); + } else { + note_a = ps->song.notes[ps->current_note - 1]; + } + note_b = ps->song.notes[ps->current_note]; + unsigned int dur_a = getMillisecondsPerNote(ps->song) / note_a.duration; + elapsed_time = dur_a / 2 + current_note_elapsed_time; + } else { + // We are on the upper half of the current note. + if (ps->current_note == ps->song.size - 1) { + note_b = makeNote(ps->song.minFreq, 4); + } else { + note_b = ps->song.notes[ps->current_note + 1]; + } + note_a = ps->song.notes[ps->current_note]; + elapsed_time = current_note_elapsed_time - (current_note_dur / 2); + } + dur_a = getMillisecondsPerNote(ps->song) / note_a.duration; + dur_b = getMillisecondsPerNote(ps->song) / note_b.duration; + float t = ((float) elapsed_time) / (dur_a / 2 + dur_b / 2); + float intensity_a = getRelativeNoteIntensity(note_a, ps->song); + float intensity_b = getRelativeNoteIntensity(note_b, ps->song); + + // linear + //return (1 - t) * intensity_a + t * intensity_b; + + // cubic + float y0 = intensity_a; + float y1 = y0; + float y2 = intensity_b; + float y3 = y2; + float n = 1 - t; + + return n*n*n*y0 + 3*t*n*n*y1 + 3*t*t*n*y2 + t*t*t*y3; +} + +#endif diff --git a/nightlight.ino b/nightlight.ino new file mode 100644 index 0000000..6f759c9 --- /dev/null +++ b/nightlight.ino @@ -0,0 +1,121 @@ +#include "music.h" +#include "songs.h" +#include "light.h" + +#define BUZZER 11 +#define LED_RED 6 +#define LED_GREEN 9 +#define LED_BLUE 10 +#define BUTTON_IN 12 + +// Standard delay of 30 milliseconds for slightly above 30fps. +#define STD_DELAY 30 + +// MUSIC CONTROL + +struct PlayingSong mc_playing_song; + +// Begins playing a new song. +void mc_play_song() { + long choice = random(0, SONG_COUNT); + playSong(&mc_playing_song, SONGS[choice]); +} + +// Updates the music controller, playing a note if needed. +void mc_update(unsigned int elapsed_ms) { + struct Note* note_to_play = updateSong(&mc_playing_song, elapsed_ms); + if (note_to_play != NULL) { + tone(BUZZER, note_to_play->frequency, getMillisecondsPerNote(mc_playing_song.song) / note_to_play->duration); + } +} + +// LIGHT CONTROL + +unsigned int lc_elapsed_ms; +unsigned char lc_chosen_time_function = 0; + +void lc_cycle_function() { + lc_chosen_time_function++; + if (lc_chosen_time_function >= LC_TIME_FUNCTION_COUNT) { + lc_chosen_time_function = 0; + } +} + +void lc_set_led(float r, float g, float b) { + analogWrite(LED_RED, r * 255); + analogWrite(LED_GREEN, g * 255); + analogWrite(LED_BLUE, b * 255); +} + +void lc_set_color(Color c) { + lc_set_led(c.r, c.g, c.b); +} + +void lc_update(unsigned int elapsed_ms) { + lc_elapsed_ms += elapsed_ms; + if (lc_elapsed_ms > LC_PERIOD) lc_elapsed_ms -= LC_PERIOD; + if (mc_playing_song.playing) { + float i = getInterpolatedRelativeIntensity(&mc_playing_song); + //Serial.println(i); + lc_set_color({i, i, i}); + } else { + lc_set_color(LC_TIME_FUNCTIONS[lc_chosen_time_function](lc_elapsed_ms)); + } +} + +// INPUT MANAGEMENT + +#define IM_CLICK_DELAY 500 + +bool im_button_pressed = false; +unsigned long im_ms_since_press = 10000; +unsigned char im_press_count = 0; + +void im_update(unsigned int elapsed_ms) { + im_ms_since_press += elapsed_ms; + if (im_ms_since_press > 1000000000) im_ms_since_press = 10000; // Reset counter to avoid overflow. + int state = digitalRead(BUTTON_IN); + + if (!im_button_pressed && state == HIGH) { + im_button_pressed = true; + } + + if (im_button_pressed && state == LOW) { + im_button_pressed = false; + im_press_count++; + im_ms_since_press = 0; + } + + if (im_ms_since_press > IM_CLICK_DELAY) { + if (im_press_count == 1) { + mc_play_song(); + } else if (im_press_count == 2) { + lc_cycle_function(); + } else if (im_press_count == 3) { + mc_play_song(); + lc_cycle_function(); + } + im_press_count = 0; + } +} + +void setup() { + randomSeed(analogRead(0)); // Read analog noise to inialize random numbers. + pinMode(BUZZER, OUTPUT); + pinMode(LED_RED, OUTPUT); + pinMode(LED_GREEN, OUTPUT); + pinMode(LED_BLUE, OUTPUT); + pinMode(BUTTON_IN, INPUT); + //playSong(&mc_playing_song, SONG_TEST); + pinMode(13, OUTPUT); + digitalWrite(12, LOW); + + //Serial.begin(9600); +} + +void loop() { + delay(STD_DELAY); + mc_update(STD_DELAY); + lc_update(STD_DELAY); + im_update(STD_DELAY); +} diff --git a/pitches.h b/pitches.h new file mode 100644 index 0000000..54dc5a3 --- /dev/null +++ b/pitches.h @@ -0,0 +1,90 @@ +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 +#define NOTE_REST 0 diff --git a/songs.h b/songs.h new file mode 100644 index 0000000..f561ea1 --- /dev/null +++ b/songs.h @@ -0,0 +1,195 @@ +#include "music.h" + +const struct Note SONG_SKYRIM_NOTES[] = { + makeNote(NOTE_D5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_F5, 8 / 3), + makeNote(NOTE_F5, 8), + makeNote(NOTE_F5, 8), + makeNote(NOTE_G5, 8), + makeNote(NOTE_A5, 8 / 3), + makeNote(NOTE_A5, 8), + makeNote(NOTE_A5, 8), + makeNote(NOTE_C5, 8),//10 + makeNote(NOTE_G5, 8 / 3), + makeNote(NOTE_G5, 8), + makeNote(NOTE_F5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_D5, 8 / 3), + makeNote(NOTE_D5, 8), + makeNote(NOTE_D5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_F5, 8 / 3), + makeNote(NOTE_F5, 8),//20 + makeNote(NOTE_F5, 8), + makeNote(NOTE_G5, 8), + makeNote(NOTE_A5, 8 / 3), + makeNote(NOTE_A5, 8), + makeNote(NOTE_A5, 8), + makeNote(NOTE_C5, 8), + makeNote(NOTE_D5, 8 / 3), + makeNote(NOTE_D5, 8), + makeNote(NOTE_C5, 8), + makeNote(NOTE_E5, 8),//30 + makeNote(NOTE_D5, 8 / 3), + makeNote(NOTE_D5, 8), + makeNote(NOTE_D5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_F5, 4), + makeNote(NOTE_E5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_D5, 4), + makeNote(NOTE_C5, 4), + makeNote(NOTE_B5, 8),//40 + makeNote(NOTE_B5, 8), + makeNote(NOTE_A5, 4), + makeNote(NOTE_G5, 8 / 3), + makeNote(NOTE_G5, 8), + makeNote(NOTE_F5, 8), + makeNote(NOTE_A5, 8), + makeNote(NOTE_G5, 8 / 3), + makeNote(NOTE_G5, 4), + makeNote(NOTE_F5, 16), + makeNote(NOTE_E5, 16),//50 + makeNote(NOTE_F5, 4), + makeNote(NOTE_F5, 16), + makeNote(NOTE_E5, 16), + makeNote(NOTE_F5, 4), + makeNote(NOTE_F5, 16), + makeNote(NOTE_E5, 16), + makeNote(NOTE_G5, 8), + makeNote(NOTE_F5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_D5, 4),//60 + makeNote(NOTE_D5, 16), + makeNote(NOTE_C5, 16), + makeNote(NOTE_D5, 4), + makeNote(NOTE_D5, 16), + makeNote(NOTE_C5, 16), + makeNote(NOTE_D5, 4), + makeNote(NOTE_C5, 16), + makeNote(NOTE_D5, 16), + makeNote(NOTE_E5, 8), + makeNote(NOTE_F5, 8),//70 + makeNote(NOTE_C5, 8), + makeNote(NOTE_D5, 4), + makeNote(NOTE_D5, 16), + makeNote(NOTE_E5, 16), + makeNote(NOTE_F5, 4), + makeNote(NOTE_F5, 16), + makeNote(NOTE_G5, 16), + makeNote(NOTE_A5, 4), + makeNote(NOTE_E5, 16), + makeNote(NOTE_F5, 16),//80 + makeNote(NOTE_G5, 8), + makeNote(NOTE_F5, 8), + makeNote(NOTE_E5, 8), + makeNote(NOTE_D5, 4), + makeNote(NOTE_D5, 16), + makeNote(NOTE_C5, 16), + makeNote(NOTE_D5, 4), + makeNote(NOTE_D5, 16), + makeNote(NOTE_C5, 16), + makeNote(NOTE_D5, 4),//90 + makeNote(NOTE_C5, 16), + makeNote(NOTE_D5, 16), + makeNote(NOTE_E5, 8), + makeNote(NOTE_F5, 8), + makeNote(NOTE_C5, 8), + makeNote(NOTE_D5, 8 / 3), + makeNote(NOTE_D5, 4), + makeNote(NOTE_REST, 8), + makeNote(NOTE_D5, 4), + makeNote(NOTE_REST, 8),//100 + makeNote(NOTE_D5, 4), + makeNote(NOTE_REST, 8), + makeNote(NOTE_D5, 4), + makeNote(NOTE_REST, 8) +}; + +const struct Song SONG_SKYRIM = makeSong(120, 104, SONG_SKYRIM_NOTES); + +const struct Note SONG_HOBBIT_NOTES2[] = { + makeNote(NOTE_D2, 4), + makeNote(NOTE_A2, 4), + makeNote(NOTE_D3, 4), + makeNote(NOTE_A2, 4), + makeNote(NOTE_D2, 4), + makeNote(NOTE_A2, 4), + makeNote(NOTE_D3, 4), + makeNote(NOTE_REST, 4), + makeNote(NOTE_D5, 16), + makeNote(NOTE_E5, 8), + makeNote(NOTE_FS5, 4), + makeNote(NOTE_A5, 4), + makeNote(NOTE_FS5, 8), + makeNote(NOTE_E5, 16), + makeNote(NOTE_FS5, 16), + makeNote(NOTE_E5, 16), + makeNote(NOTE_D5, 1.5), + makeNote(NOTE_REST, 8), + makeNote(NOTE_FS5, 4), + makeNote(NOTE_A5, 8), + makeNote(NOTE_B5, 4.0/3), + makeNote(NOTE_D6, 8), + makeNote(NOTE_CS6, 4.0/3), + makeNote(NOTE_A5, 8), + makeNote(NOTE_FS5, 4.0/3), + makeNote(NOTE_G5, 16), + makeNote(NOTE_FS5, 16), + makeNote(NOTE_E5, 4.0/3), + makeNote(NOTE_D5, 16), + makeNote(NOTE_E5, 16), + makeNote(NOTE_FS5, 4), + makeNote(NOTE_A5, 4), + makeNote(NOTE_FS5, 16), + makeNote(NOTE_E5, 8), + makeNote(NOTE_D5, 8), + makeNote(NOTE_E5, 16), + makeNote(NOTE_D5, 1.5), + makeNote(NOTE_REST, 8), + makeNote(NOTE_FS5, 4), + makeNote(NOTE_A5, 8), + makeNote(NOTE_B5, 1.5), + makeNote(NOTE_A5, 4), + makeNote(NOTE_FS5, 4), + makeNote(NOTE_FS5, 1.5), + makeNote(NOTE_E5, 1.5), + makeNote(NOTE_D5, 16), + makeNote(NOTE_E5, 8), + makeNote(NOTE_D5, 4.0/3), + makeNote(NOTE_D3, 4), + makeNote(NOTE_A2, 4), + makeNote(NOTE_D2, 4), + makeNote(NOTE_A2, 4), + makeNote(NOTE_D3, 4), + makeNote(NOTE_A2, 4) +}; + +const struct Song SONG_HOBBIT = makeSong(104, 54, SONG_HOBBIT_NOTES2); + +const struct Note SONG_TEST_NOTES[] = { + makeNote(NOTE_A1, 4), + makeNote(NOTE_A2, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A4, 4), + makeNote(NOTE_A5, 4), + makeNote(NOTE_A6, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A6, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A6, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A6, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A6, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A6, 4), + makeNote(NOTE_A3, 4), + makeNote(NOTE_A6, 4) +}; + +const struct Song SONG_TEST = makeSong(60, 18, SONG_TEST_NOTES); + +const struct Song SONGS[] = {SONG_SKYRIM, SONG_HOBBIT}; +#define SONG_COUNT 2