/* MP3 Stuff */
#include <mp3.h>
#include <mp3conf.h>
#define MP3_CS 5 // 'command chip select' to cs pin
#define DCS 14 // (Pin A0) 'data chip select' to bsync pin
#define RST 6 // 'reset' to decoder's reset pin
#define DREQ 15 // (Pin A1) 'data request line' to dreq pin
/* SD Stuff */
#include <SD.h>
#define SD_CS 4 // 'chip select' for SD card
static int clickingFinishedPin = 7;
#define MAX_FILE_COUNT 30
#define READ_BUFFER_SIZE 256 // Size of the microSD read buffer
Sd2Card card;
SdVolume volume;
SdFile root;
char **files;
int numFiles;
int currentFileIndex = -1;
byte playbackVolume = 230;
boolean dialing = false;
volatile boolean playing = false;
volatile int numClicks = 0;
unsigned long howFarIn = 0;
unsigned char bytes[READ_BUFFER_SIZE]; // buffer to send to the decoder
unsigned int numBytesRead; // number of bytes read from sd card
SdFile currentFile;
unsigned long lastCheckTime = 0;
enum Mode {
MODE_NORMAL,
MODE_SET_VOLUME,
MODE_SEARCH
};
int control_mode = MODE_NORMAL;
enum ModeLights {
PLAYING_LIGHT,
SET_VOLUME_LIGHT,
SEARCH_LIGHT
};
static int lightPins[] = {0, 9, 2};
int listMP3Files(SdFile *dir, char **buf) {
int count = 0;
dir_t p;
dir->rewind();
while (dir->readDir(&p) > 0 && count < MAX_FILE_COUNT) {
// done if past last used entry
if (p.name[0] == DIR_NAME_FREE) break;
if (DIR_IS_SUBDIR(&p)) continue;
// skip deleted entry and entries for . and ..
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;
// only list files
if (!DIR_IS_FILE(&p)) continue;
if(p.name[8] != 'M' || p.name[9] != 'P' || p.name[10] != '3') continue;
char nameBuf[13];
uint8_t pos = 0;
for (uint8_t i = 0; i < 8; i++) {
if (p.name[i] != ' ') {
nameBuf[pos] = (char)p.name[i];
pos++;
}
}
nameBuf[pos] = '.';
nameBuf[pos+1] = (char)p.name[8];
nameBuf[pos+2] = (char)p.name[9];
nameBuf[pos+3] = (char)p.name[10];
pos += 4;
// add the null terminator
nameBuf[pos] = '\0';
buf[count] = strdup((const char *)nameBuf);
count++;
}
return count;
}
void switch_mode_light(int light, int state) {
digitalWrite(lightPins[light], state);
}
void play_music() {
Serial.println("Playing...");
switch_mode_light(PLAYING_LIGHT, HIGH);
}
void pause_music() {
Serial.println("Stopping...");
switch_mode_light(PLAYING_LIGHT, LOW);
}
void skip_forward() {
Serial.println("Skipping forward...");
Serial.println(currentFileIndex);
numBytesRead = 0;
}
void skip_backwards() {
Serial.println("Skipping backwards...");
Serial.println(howFarIn);
numBytesRead = 0;
if(howFarIn < 500){
currentFileIndex -= 2;
}else{
currentFileIndex--;
}
}
void set_volume(int v) {
Serial.print("Seting volume to ");
Serial.println(v);
Mp3.volume(map(v, 0, 10, 0, 254));
}
void handleHook() {
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 8) {
playing = (digitalRead(3) == LOW);
if(playing){
play_music();
}else{
pause_music();
}
}
last_interrupt_time = interrupt_time;
}
void performAction(int action) {
switch(action){
case 1:
skip_forward();
break;
case 2:
skip_backwards();
break;
case 3:
control_mode = MODE_SET_VOLUME;
switch_mode_light(SET_VOLUME_LIGHT, HIGH);
break;
// case 4:
// control_mode = MODE_SEARCH;
// switch_mode_light(SEARCH_LIGHT, HIGH);
// break;
}
}
void handleClick() {
static unsigned long last_interrupt_time = 0;
unsigned long interrupt_time = millis();
if (interrupt_time - last_interrupt_time > 20) {
++numClicks;
}
last_interrupt_time = interrupt_time;
}
void setup() {
Serial.begin(9600);
pinMode(clickingFinishedPin, INPUT);
digitalWrite(clickingFinishedPin, HIGH);
attachInterrupt(0, handleClick, CHANGE);
attachInterrupt(1, handleHook, CHANGE);
pinMode(3, INPUT); // Interrupt pin 1
playing = (digitalRead(3) == LOW);
pinMode(10, OUTPUT);
if (!card.init(SPI_HALF_SPEED, 4)) {
Serial.println("initialization failed!");
return;
}
if (!volume.init(card)) {
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
return;
}
root.openRoot(volume);
files = (char **)malloc(MAX_FILE_COUNT * sizeof(char *));
numFiles = listMP3Files(&root, files);
Serial.print("Found ");
Serial.print(numFiles);
Serial.println(" files:");
for(int i = 0; i < numFiles; ++i){
int nameLen = strlen(files[i]);
Serial.println(files[i]);
}
Mp3.begin(MP3_CS, DCS, RST, DREQ); // decoder cs, dcs, rst, dreq pin
Mp3.volume(playbackVolume); // default volume level is silent
}
void loop() {
if(playing){
if(numBytesRead != READ_BUFFER_SIZE) { // Change songs
currentFileIndex++;
if(currentFileIndex >= numFiles) currentFileIndex = 0;
Serial.print("Opening file: ");
Serial.println(files[currentFileIndex]);
currentFile.close();
if(currentFile.open(root, files[currentFileIndex], O_RDONLY) > 0){
currentFile.seekSet(0);
Serial.print("Playing file: ");
Serial.println(files[currentFileIndex]);
howFarIn = 0;
numBytesRead = currentFile.read(bytes, READ_BUFFER_SIZE);
}else{
Serial.println("Error opening file!");
currentFileIndex++;
}
}else{
numBytesRead = currentFile.read(bytes, READ_BUFFER_SIZE);
Mp3.play(bytes, numBytesRead);
howFarIn++;
}
}
unsigned long currTime = millis();
if(currTime >= lastCheckTime + 10){
int clickingState = digitalRead(clickingFinishedPin);
if(!dialing && clickingState == LOW){
dialing = true;
}else if(dialing && clickingState == HIGH){
numClicks /= 2;
Serial.println(numClicks);
if(control_mode == MODE_NORMAL){
performAction(numClicks);
}else if(control_mode == MODE_SET_VOLUME){
set_volume(numClicks);
control_mode = MODE_NORMAL;
switch_mode_light(SET_VOLUME_LIGHT, LOW);
}
numClicks = 0;
dialing = false;
}
lastCheckTime = currTime;
}
}
Comments (0)
You don't have permission to comment on this page.