From 43638abc8bde8a3193ef674bef49f7e70c760a28 Mon Sep 17 00:00:00 2001 From: caternuson Date: Tue, 24 Oct 2017 13:46:08 -0700 Subject: [PATCH] make it not sub --- .../Gordon_Cole_MP3_Player.ino | 242 ++++++++++++++++++ Gordon_Cole_MP3_Player/LICENSE | 21 ++ Gordon_Cole_MP3_Player/README.md | 2 + 3 files changed, 265 insertions(+) create mode 100644 Gordon_Cole_MP3_Player/Gordon_Cole_MP3_Player.ino create mode 100644 Gordon_Cole_MP3_Player/LICENSE create mode 100644 Gordon_Cole_MP3_Player/README.md diff --git a/Gordon_Cole_MP3_Player/Gordon_Cole_MP3_Player.ino b/Gordon_Cole_MP3_Player/Gordon_Cole_MP3_Player.ino new file mode 100644 index 000000000..42e3e956c --- /dev/null +++ b/Gordon_Cole_MP3_Player/Gordon_Cole_MP3_Player.ino @@ -0,0 +1,242 @@ +// +// Gordon Cole MP3 Player +// + +#include +#include +#include + +// 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; +} diff --git a/Gordon_Cole_MP3_Player/LICENSE b/Gordon_Cole_MP3_Player/LICENSE new file mode 100644 index 000000000..377370b0c --- /dev/null +++ b/Gordon_Cole_MP3_Player/LICENSE @@ -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. diff --git a/Gordon_Cole_MP3_Player/README.md b/Gordon_Cole_MP3_Player/README.md new file mode 100644 index 000000000..dd6ea9afa --- /dev/null +++ b/Gordon_Cole_MP3_Player/README.md @@ -0,0 +1,2 @@ +# Gordon_Cole_MP3_Player +Arduino code for simple MP3 player.