-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMusicPlayerTemplate.txt
148 lines (123 loc) · 4.15 KB
/
MusicPlayerTemplate.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// MUSIC GOES HERE:
###MUSICDATA###
// The pin the piezoelectric buzzer is connected to.
const int PIEZO_PIN = 6;
// Pin the start/stop or reset music... Set to -1 to disable...
const int ON_PIN = 3;
// Enable/Disable external timing/syncing. Useful if trying to use multiple arduino's at once...
const bool SYNC_EXTERNAL = false;
// The update pin, if external syncing is on...
const int UPDATE_PIN = 2;
// Enable/Disable send a millisecond syncing signal.
const bool SEND_SYNC_SIGNAL = false;
// If sending syncing information is enabled, send it on this pin...
const int SEND_SYNC_PIN = 8;
// Set the selected song...
const auto &SELECTED_SONG = ###TRACKNAME###;
const auto &SELECTED_SONG_LENGTH = ###TRACKNAME###Len;
const auto &SELECTED_SONG_TICK_SPEED = ###TRACKNAME###MillisPerTick;
// Enable/Disable Debuging, which pin to read data in on...
const bool DEBUG = false;
const int DEBUG_READ_PIN = A3;
// END OF CONFIGURATION...
/*
* MUSIC PLAYING CODE BELOW:
*/
int toFrequency(uint16_t midi_num) {
return (int)(pow(2, (((double)midi_num / 128.0) - 69) / 12) * 440);
}
// Stash current state of the music player....
bool syncState = false;
size_t nextNote = 0;
unsigned long lastSyncSendSwitch = 0;
unsigned long lastNoteTime = 0;
unsigned long currentTime = 0;
float noteDuration = 0;
void setup() {
// Setup code...
if(SYNC_EXTERNAL) {
// If syncing is set up, configure interrupt to update internal millis function...
pinMode(UPDATE_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(UPDATE_PIN), updateSync, CHANGE);
}
// Configure output/on pin...
pinMode(PIEZO_PIN, OUTPUT);
if(SEND_SYNC_SIGNAL) pinMode(SEND_SYNC_PIN, OUTPUT);
if(ON_PIN >= 0) pinMode(ON_PIN, INPUT_PULLUP);
lastNoteTime = getTime();
currentTime = getTime();
if constexpr(DEBUG) {
Serial.begin(9600);
pinMode(DEBUG_READ_PIN, INPUT);
}
}
// Grabs correct millisecond timing function based on config, and calls it...
unsigned long getTime() {
if constexpr(SYNC_EXTERNAL) {
return syncedMillis();
}
else {
return millis();
}
}
const uint16_t DATA_MASK = 0b0011111111111111;
void loop() {
// Loop code... Repeats forever...
// Get the current time...
currentTime = getTime();
// If one millisecond has passed, toggle the sync pin if enabled...
if(SEND_SYNC_SIGNAL && ((currentTime - lastSyncSendSwitch) >= 1)) {
lastSyncSendSwitch = currentTime;
syncState = !syncState;
digitalWrite(SEND_SYNC_PIN, syncState);
}
// If on, keep playing, otherwise reset the song...
if((SELECTED_SONG_LENGTH > 0) && ((ON_PIN < 0) || (digitalRead(ON_PIN) == HIGH))) {
// If the time passed is equal to at least the note duration, play the next note
if((currentTime - lastNoteTime) >= noteDuration) {
// Read the next note.
uint16_t noteData = (uint16_t *)pgm_read_word(&SELECTED_SONG[nextNote]);
// Set lastNoteTime to the current time...
lastNoteTime = currentTime;
switch((noteData >> 14) & 0b11) {
case 0b00:
// Wait command, copy over the wait time...
noteDuration = ((float)(noteData & DATA_MASK)) * SELECTED_SONG_TICK_SPEED;
break;
case 0b01:
// Play command, push tone to buzzer pin, set duration to 0 so next instruction is executed immediately.
tone(PIEZO_PIN, toFrequency(noteData & DATA_MASK));
noteDuration = 0;
break;
case 0b10:
// Rest command, stop tone playing, copy over the wait time...
noTone(PIEZO_PIN);
noteDuration = ((float)(noteData & DATA_MASK)) * SELECTED_SONG_TICK_SPEED;
break;
default:
noteDuration = 0;
break;
}
// Update nextNote to point to the next note in the song...
nextNote = (nextNote + 1) % SELECTED_SONG_LENGTH;
}
}
else {
// Reset the music player to the begining...
noTone(PIEZO_PIN);
nextNote = 0;
noteDuration = 0;
lastNoteTime = currentTime;
}
if constexpr(DEBUG) {
Serial.println(analogRead(DEBUG_READ_PIN));
}
}
// Syncing interrupt if syncing is enabled...
volatile unsigned long mils = 0;
unsigned long syncedMillis() {
return mils;
}
void updateSync() {
mils++;
}