-
Notifications
You must be signed in to change notification settings - Fork 0
/
music_player.ino
283 lines (242 loc) · 9.17 KB
/
music_player.ino
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/***************************************************
Designed for audio surprises.
Outline:
1) Play interruptable file when shaken.
2) Play file when hall effect sensor triggered (lid opened)
3) After file finishes from lid opening, continue to play random files
at random intervals forever.
Code written by: Carlin Kartchner
Outline for player began with Adafruit VS1053 example code, player_simple
Written by Limor Fried/Ladyada for Adafruit Industries.
Thanks to Puck on StackOverflow for random file implementation:
https://stackoverflow.com/questions/26002991/arduino-random-file-on-sd-rewinddirectory
Sections user will want to consider editing:
- User editable globals section
- Files played. Obviously not everyone will have the same files.
- All code pertaining to the use of an LSM303 for shake detection as there are many ways to do this.
Known issues:
-Higher bitrate wav files will not play correctly with many microcontrollers due to a slower clock rate that cannot keep up.
Consider converting the wav to a compressed format for better performance.
****************************************************/
// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include <Wire.h>
#include <LSM303.h>
// These are the pins used for the breakout
#define BREAKOUT_RESET 9 // VS1053 reset pin (output)
#define BREAKOUT_CS 10 // VS1053 chip select pin (output)
#define BREAKOUT_DCS 8 // VS1053 Data/command select pin (output)
#define CARDCS 4 // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3 // VS1053 Data request, ideally an Interrupt pin
// Trigger pin setup
const int lidSwitch = 0;
// User editable globals
const int amag_trigger = 1.3; //This should be tested at final location before use. Sensitivity may vary between environments.
const int vol = 30; //Volume. Lower number -> louder volume.
// Files played. Should be edited by end user.
const char trigger_audio[] = "Tron//17DISC~1.WMA"; //File played when switch is triggered.
const char ready_audio[] = "PowUp.wma"; //Audio played when signaling the packge is ready to be triggered on opening.
const char shake_audio[] = "meow~1.fla"; //Audio played when shaking is triggered
const char random_dir[] = "wavs/"; //Folder containing random file clips
// Initialize musicplayer object
Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
// Initialize accelerometer object
LSM303 compass;
// Global variables.
int lss = 0; //lid switch state
int n_files = 0; //number of files counted by countFiles
int rcnt = 0; //Tracker for number of random counts played.
float amag = 0.0; //accelerometer magnitude
void setup() {
Serial.begin(9600);
Serial.println("Initializing music player");
Wire.begin();
//Initialize LSM303 for accelerometer (shaking) readings
compass.init();
compass.enableDefault();
//generate a random seed so it doesn't do the same order every time!
randomSeed(analogRead(0));
if (! musicPlayer.begin()) { // initialise the music player
Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
while (1);
}
Serial.println(F("VS1053 found"));
//SD.begin() needs to be called before doing other SD card communication!
if (!SD.begin(CARDCS)) {
Serial.println(F("SD failed, or not present"));
while (1); // don't do anything more
}
File folder = SD.open(random_dir);
n_files = countFiles(folder);
folder.close();
//Unclear why, but if F() missing from Serial.print below, files won't play!
//F() causes flash based memory strings to be used.
Serial.print(F("Number of files in random audio dir: "));
Serial.println(n_files);
// list all files on SD card
// printDirectory(SD.open("/"), 0);
// Set volume for left, right channels. lower numbers == louder volume!
// Remember, what sounds good during testing may not be audible in a loud environment.
musicPlayer.setVolume(vol, vol);
// If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background
// audio playing
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int
// Setup trigger switch
pinMode(lidSwitch, INPUT);
// Wait a min to get lid closed. Gives ample time to get setup before trigger is enabled.
Serial.println(F("Start of 1 min wait."));
unsigned long startMillis = millis();
while (millis() - startMillis < 60000);
Serial.println(F("End of 1 min wait."));
//play tone announcing the pkg is ready and g2g.
musicPlayer.playFullFile(ready_audio);
}
void loop() {
//Check if player is making sudden movements or shaking
//default FS linear acceleration = +/- 2g
//mg/LSB = 0.061
compass.read();
float ax = compass.a.x;
float ay = compass.a.y;
float az = compass.a.z;
amag = sqrt(ax*ax + ay*ay + az*az); //magnitude of acceleration
amag = amag*0.000061; //normalize (not calibrated, so doesn't equal 1)
if (amag > 1.3) {
Serial.println(F("Shaking detected!"));
if (musicPlayer.stopped()) {
Serial.println(F("Trying to play shaking audio"));
musicPlayer.startPlayingFile(shake_audio);
}
}
//Check if box has been opened
//Will interrupt shaking audio if currently playing.
lss = digitalRead(lidSwitch);
if (lss == 1){ //Pin goes HIGH when magnet is removed.
Serial.println(F("Hall Effect switch detected!"));
musicPlayer.stopPlaying();
Serial.println(F("Music stopped!"));
int status = musicPlayer.playingMusic;
Serial.print(F("Is music playing:")); Serial.println(status);
musicPlayer.softReset(); //allows for playing with interrupt!
Serial.println(F("Soft reset preformed"));
musicPlayer.playFullFile(trigger_audio);
//After trigger music is finished, play random audio.
randomAudio();
}
delay(500);
}
// Play a random audio file
void playRandomAudio(){
int i, rand_song;
rcnt++;
File folder = SD.open(random_dir);
File random_file;
rand_song = random(0, n_files)+1;
Serial.print(F("Random audio attempt: ")); Serial.println(rcnt);
Serial.print(F("Random number: ")); Serial.println(rand_song);
folder.rewindDirectory();
random_file = selectFileN(rand_song, folder);
folder.close();
Serial.print(F("Trying to play:")); Serial.println(random_file.name());
//Uncertain if this is the best way to concatenate these strings, but it works!
String lstr = String(random_dir) + String(random_file.name());
Serial.print(F("Stated playing file:"));
Serial.println(lstr);
if(!musicPlayer.playFullFile(lstr.c_str())) {
Serial.println(F("Could not open audio file"));
}
else Serial.println(F("Finished play attempt!"));
random_file.close();
Serial.println();
Serial.println();
}
void randomAudio(){
double dtime;
//Unsure if this reset is still required, but it doesn't seem to cause any problems
//Added when problems seen if the initial shaking audio was inturrupted by lid opening audio.
musicPlayer.softReset(); //allows for playing with interrupt!
Serial.println(F("Soft reset preformed"));
//Play initial random sound after 3 sec delay so audience knows to expect random audio.
unsigned long startMillis = millis();
while (millis() - startMillis < 3000);
playRandomAudio();
//Play audio file after random interval
while(true) {
//delay between 1 seconds and 5 minutes
dtime = random(1000,300000);
//delay between 1 and 5 seconds
//dtime = random(1000, 5000);
Serial.print(F("Delay time:")); Serial.println(dtime);
unsigned long startMillis = millis();
while (millis() - startMillis < dtime);
playRandomAudio();
}
}
// Select random file number
File selectFileN(int number, File dir) {
int counter = 0;
File return_entry;
while(true) {
File entry = dir.openNextFile();
if (! entry) {
Serial.println(F("Last file reached"));
dir.rewindDirectory();
break;
}
Serial.println(entry.name());
counter++;
if(counter==number) {
return_entry = entry;
dir.rewindDirectory();
break;
}
entry.close();
}
return return_entry;
}
// Count the number of files in a given directory
int countFiles(File dir) {
Serial.println(F("Counting files"));
int counter = 0;
while(true) {
File entry = dir.openNextFile();
if (! entry) {
dir.rewindDirectory();
break;
}
Serial.println(entry.name());
counter++;
entry.close();
}
Serial.println("----------------");
return counter;
}
// File listing helper
// Included with many examples of the Arduino SD library
// Useful when adding new audio files.
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
//Serial.println("**nomorefiles**");
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print(F("\t\t"));
Serial.println(entry.size(), DEC);
}
entry.close();
}
}