make it not sub
This commit is contained in:
parent
9c3c4db525
commit
43638abc8b
3 changed files with 265 additions and 0 deletions
242
Gordon_Cole_MP3_Player/Gordon_Cole_MP3_Player.ino
Normal file
242
Gordon_Cole_MP3_Player/Gordon_Cole_MP3_Player.ino
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
//
|
||||
// Gordon Cole MP3 Player
|
||||
//
|
||||
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <Adafruit_VS1053.h>
|
||||
|
||||
// Guide is based on Feather M0 Express
|
||||
// ARDUINO_SAMD_FEATHER_M0 defines only
|
||||
// VS1053 Pins
|
||||
#define VS1053_RESET -1 // VS1053 reset pin (not used!)
|
||||
#define VS1053_CS 6 // VS1053 chip select pin (output)
|
||||
#define VS1053_DCS 10 // VS1053 Data/command select pin (output)
|
||||
#define CARDCS 5 // Card chip select pin
|
||||
#define VS1053_DREQ 9 // VS1053 Data request, ideally an Interrupt pin
|
||||
// Button Pins
|
||||
#define BUTTON_PLAY 13 // PLAY / STOP button
|
||||
#define BUTTON_PAUSE 12 // PAUSE / RESUME button
|
||||
#define BUTTON_NEXT 11 // NEXT button
|
||||
// Status LED
|
||||
#define LED_STATUS 19 // status LED
|
||||
#define BLINK_RATE 500 // blink rate in ms
|
||||
// Volume Control
|
||||
#define KNOB_VOLUME 0 // volume knob
|
||||
#define KNOB_MIN 0 // min ADC value
|
||||
#define KNOB_MAX 1023 // max ADC value
|
||||
#define VOL_MIN 0 // min volume (most loud)
|
||||
#define VOL_MAX 50 // max volume (most quiet)
|
||||
// Maximum number of files (tracks) to load
|
||||
#define TRACKS_MAX 100
|
||||
// Player behavior
|
||||
#define AUTO_PLAY_NEXT true // true to automatically go to next track
|
||||
|
||||
unsigned long currentMillis, previousMillis;
|
||||
int currentKnob, previousKnob;
|
||||
int volume;
|
||||
int currentTrack, totalTracks;
|
||||
char trackListing[TRACKS_MAX][13] = {' '};
|
||||
enum mode {
|
||||
PLAYING,
|
||||
PAUSED,
|
||||
STOPPED
|
||||
} currentMode = STOPPED;
|
||||
|
||||
Adafruit_VS1053_FilePlayer musicPlayer =
|
||||
Adafruit_VS1053_FilePlayer(VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ, CARDCS);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
// Leave commented for standalone operation, uncomment for troubleshooting
|
||||
//while (!Serial) ;
|
||||
|
||||
// Initialize pins
|
||||
pinMode(BUTTON_PLAY, INPUT_PULLUP);
|
||||
pinMode(BUTTON_PAUSE, INPUT_PULLUP);
|
||||
pinMode(BUTTON_NEXT, INPUT_PULLUP);
|
||||
pinMode(LED_STATUS, OUTPUT);
|
||||
|
||||
// Initialize status LED
|
||||
previousMillis = millis();
|
||||
digitalWrite(LED_STATUS, LOW);
|
||||
|
||||
Serial.println("\n\nGordon Cole MP3 Player");
|
||||
|
||||
// Initialize the music player
|
||||
if (! musicPlayer.begin()) {
|
||||
Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
|
||||
while (1);
|
||||
}
|
||||
Serial.println(F("VS1053 found"));
|
||||
musicPlayer.softReset();
|
||||
|
||||
// Make a tone to indicate VS1053 is working
|
||||
musicPlayer.sineTest(0x44, 500);
|
||||
|
||||
// Set volume for left, right channels. lower numbers == louder volume!
|
||||
previousKnob = analogRead(KNOB_VOLUME);
|
||||
volume = map(previousKnob, KNOB_MIN, KNOB_MAX, VOL_MIN, VOL_MAX);
|
||||
Serial.print("Volume = "); Serial.println(volume);
|
||||
musicPlayer.setVolume(volume, volume);
|
||||
|
||||
// Initialize the SD card
|
||||
if (!SD.begin(CARDCS)) {
|
||||
Serial.println(F("SD failed, or not present"));
|
||||
while (1);
|
||||
}
|
||||
Serial.println("SD OK!");
|
||||
|
||||
// Load list of tracks
|
||||
Serial.println("Track Listing");
|
||||
Serial.println("=============");
|
||||
totalTracks = 0;
|
||||
loadTracks(SD.open("/"), 0);
|
||||
currentTrack = 0;
|
||||
|
||||
// Setup interrupts (DREQ) for playback
|
||||
musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void loop() {
|
||||
// Check and set volume
|
||||
updateVolume();
|
||||
|
||||
// Update status LED
|
||||
updateStatusLED();
|
||||
|
||||
// Auto play next track if feature enabled
|
||||
if (AUTO_PLAY_NEXT) {
|
||||
if (currentMode==PLAYING && musicPlayer.stopped()) {
|
||||
currentTrack = ++currentTrack < totalTracks ? currentTrack : 0;
|
||||
Serial.print("Next ");
|
||||
Serial.print(currentTrack); Serial.print("=");
|
||||
Serial.println(trackListing[currentTrack]);
|
||||
musicPlayer.startPlayingFile(trackListing[currentTrack]);
|
||||
currentMode = PLAYING;
|
||||
}
|
||||
}
|
||||
|
||||
// Start / Stop
|
||||
if (!digitalRead(BUTTON_PLAY)) {
|
||||
if (musicPlayer.stopped()) {
|
||||
Serial.print("Start ");
|
||||
Serial.print(currentTrack); Serial.print("=");
|
||||
Serial.println(trackListing[currentTrack]);
|
||||
musicPlayer.startPlayingFile(trackListing[currentTrack]);
|
||||
currentMode = PLAYING;
|
||||
} else {
|
||||
Serial.println("Stopped.");
|
||||
musicPlayer.stopPlaying();
|
||||
currentMode = STOPPED;
|
||||
}
|
||||
delay(250);
|
||||
}
|
||||
|
||||
// Pause / Resume
|
||||
if (!digitalRead(BUTTON_PAUSE)) {
|
||||
if (!musicPlayer.stopped()) {
|
||||
if (musicPlayer.paused()) {
|
||||
Serial.println("Resumed");
|
||||
musicPlayer.pausePlaying(false);
|
||||
currentMode = PLAYING;
|
||||
} else {
|
||||
Serial.println("Paused");
|
||||
musicPlayer.pausePlaying(true);
|
||||
currentMode = PAUSED;
|
||||
}
|
||||
}
|
||||
delay(250);
|
||||
}
|
||||
|
||||
// Next
|
||||
if (!digitalRead(BUTTON_NEXT)) {
|
||||
if (!musicPlayer.stopped()) {
|
||||
Serial.println("Stopping current playback.");
|
||||
musicPlayer.stopPlaying();
|
||||
}
|
||||
currentTrack = ++currentTrack < totalTracks ? currentTrack : 0;
|
||||
Serial.print("Next ");
|
||||
Serial.print(currentTrack); Serial.print("=");
|
||||
Serial.println(trackListing[currentTrack]);
|
||||
musicPlayer.startPlayingFile(trackListing[currentTrack]);
|
||||
currentMode = PLAYING;
|
||||
delay(250);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void updateVolume() {
|
||||
// Read current value
|
||||
currentKnob = analogRead(KNOB_VOLUME);
|
||||
// Only update if it's changed
|
||||
if (currentKnob != previousKnob) {
|
||||
previousKnob = currentKnob;
|
||||
volume = map(currentKnob, KNOB_MIN, KNOB_MAX, VOL_MIN, VOL_MAX);
|
||||
musicPlayer.setVolume(volume, volume);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void updateStatusLED() {
|
||||
if (musicPlayer.paused()) {
|
||||
// Blink it like a polaroid
|
||||
currentMillis = millis();
|
||||
if (currentMillis - previousMillis > BLINK_RATE) {
|
||||
previousMillis = currentMillis;
|
||||
digitalWrite(LED_STATUS, !digitalRead(LED_STATUS));
|
||||
}
|
||||
} else if (!musicPlayer.stopped()) {
|
||||
// It's so on again
|
||||
digitalWrite(LED_STATUS, HIGH);
|
||||
} else {
|
||||
// It's so off again
|
||||
digitalWrite(LED_STATUS, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void loadTracks(File dir, int level) {
|
||||
while (true) {
|
||||
File entry = dir.openNextFile();
|
||||
if (!entry) return;
|
||||
if (entry.isDirectory()) {
|
||||
// Recursive call to scan next dir level
|
||||
loadTracks(entry, level + 1);
|
||||
} else {
|
||||
// Only add files in root dir
|
||||
if (level == 0) {
|
||||
// And only if they have good names
|
||||
if (nameCheck(entry.name())) {
|
||||
strncpy(trackListing[totalTracks], entry.name(), 12);
|
||||
Serial.print(totalTracks); Serial.print("=");
|
||||
Serial.println(trackListing[totalTracks]);
|
||||
totalTracks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
entry.close();
|
||||
// Stop scanning if we hit max
|
||||
if (totalTracks >= TRACKS_MAX) return;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool nameCheck(char* name) {
|
||||
int len = strlen(name);
|
||||
// Check length
|
||||
if (len <= 4) return false;
|
||||
// Check extension
|
||||
char* ext = strrchr(name,'.');
|
||||
if (!(
|
||||
strcmp(ext,".MP3") == 0 ||
|
||||
strcmp(ext,".OGG") == 0
|
||||
)) return false;
|
||||
// Check first character
|
||||
switch(name[0]) {
|
||||
case '_': return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
21
Gordon_Cole_MP3_Player/LICENSE
Normal file
21
Gordon_Cole_MP3_Player/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 Carter Nelson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2
Gordon_Cole_MP3_Player/README.md
Normal file
2
Gordon_Cole_MP3_Player/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Gordon_Cole_MP3_Player
|
||||
Arduino code for simple MP3 player.
|
||||
Loading…
Reference in a new issue