VS1053 audio player with lcd and rotary encoder

Dependencies:   LibMenu PinDetect SDFileSystem TextLCD VS1053lib mRotaryEncoder mbed

main.cpp

Committer:
ollie8
Date:
2013-06-18
Revision:
1:0040f640281c
Parent:
0:389ef088650e
Child:
2:1c751f044ecd

File content as of revision 1:0040f640281c:

#include "mbed.h"
#include "SDFileSystem.h"
#include "VLSIcodec.h"
#include "TextLCD.h"
#include "Menu.h"
#include "mRotaryEncoder.h"

#define BUFFER_SIZE 512
#define MAX_BUF_WRITE 32

enum PlayState {
    IDLE,
    CUED,
    PLAYING,
    PAUSED
};

TextLCD lcd(p24, p25, p26, p27, p28, p29);
SDFileSystem sd(p5, p6, p7, p8, "sd");
// PinName mosi, PinName miso, PinName sclk, PinName cs, PinName dreq, PinName rst, PinName xdcs
VS1053Codec vs1053(p11, p12, p13, p14, p15, p17, p16);
mRotaryEncoder rot(p21, p22, p23);
Serial pc(USBTX, USBRX);
Menu *current;
PlayState state = IDLE;
char* currentfile;
char* lastPlaytime = (char*) malloc(6);
unsigned char volume = 0x00;

void select(MenuNode *node) {
    lcd.cls();
    lcd.printf(node->getName());
    pc.printf("Selected - %s\n\r", node->getName());
}

void cueNode(MenuNode *node) {
    currentfile = node->getName();
    state = CUED;
    pc.printf("Cueing menu node - %s\n\r", node->getName());
}

void setVolume(MenuNode *node) {

}

void setBass(MenuNode *node) {
 
}

void setTreble(MenuNode *node) {

}

void continuePlay(MenuNode *node) {
    state = PLAYING;
}


void enterMenu(Menu *menu) {
    current = menu;
    pc.printf("Entered menu - %s\n\r", menu->getName());
}

Menu root(&enterMenu, &select, "ROOT", 5);
Menu pausedMenu(&enterMenu, &select, "PAUSED", 2);

void cancelPlay(MenuNode *node) {
    state = IDLE;
    root.enter();
}

void buttonPress() {
    pc.printf("Button press");
    switch (state) {
        case IDLE:
            current->getSelectedNode().enter();
        break;
        case CUED:
            // do nothing until we start playing;
            break;
        case PLAYING:
            state = PAUSED;
            pausedMenu.enter();
        break;
        case PAUSED:
            current->getSelectedNode().enter();
        break;
    }
}

void buttonHeld() {
    pc.printf("Button held");
    state = IDLE;
    root.enter();
}

void buildLibrary() {
    DIR *d;
    struct dirent *p;
    d = opendir("/sd");
    if (d != NULL) {
        int dircount = 0;
        while ((p = readdir(d)) != NULL) {
            dircount++;
        }
        closedir(d);
        Menu *library = new Menu(&enterMenu, &select, "Library", dircount);
        root.addMenuNode(*library);
        d = opendir("/sd");
        while ((p = readdir(d)) != NULL) {
            pc.printf("Makning node\n\r");
            char * name = p->d_name;
            if (sizeof(name) > 0) {
                MenuNode *node = new MenuNode(&cueNode, &select, name);
                pc.printf("Makning node done\n\r");
                library->addMenuNode(*node);
                pc.printf("Node added\n\r");
                pc.printf(" - %s\n\r", name);
            } else {
                pc.printf("BLANK NAME");            
            }
        }
    } else {
        pc.printf("Could not open directory!\n");
    }
    closedir(d);
}

void setupMenu() {
    pc.printf("Building menus...\n\r");
    pc.printf("Menu size - %d\r\n", root.size());
    buildLibrary();
    pc.printf("Menu size - %d\r\n", root.size());
    Menu *settings = new Menu(&enterMenu, &select, "Settings", 3);
    root.addMenuNode(*settings);
    Menu *test = new Menu(&enterMenu, &select, "Test", 2);
    root.addMenuNode(*test);
    MenuNode *volume = new MenuNode(&setVolume, &select, "Volume");
    settings->addMenuNode(*volume);
    MenuNode *bass = new MenuNode(&setBass, &select, "Bass");
    settings->addMenuNode(*bass);
    MenuNode *treble = new MenuNode(&setTreble, &select, "Treble");
    settings->addMenuNode(*treble);
    pc.printf("Menu size - %d\r\n", root.size());
    MenuNode *contPlay = new MenuNode(&continuePlay, &select, "Continue");
    MenuNode *cancPlay = new MenuNode(&cancelPlay, &select, "Cancel");
    pausedMenu.addMenuNode(*contPlay);
    pausedMenu.addMenuNode(*cancPlay);
    root.enter();
    pc.printf("Done.\n\r");
}

void control() {
    int val = rot.Get();
    pc.printf("Enc val - %d", val);
    if (state == PLAYING) {
        pc.printf("\r\n");
        if (val > 1) {
            pc.printf("Going up...\r\n");
            volume -= 0x05;
            rot.Set(0);
        } else if (val < -1) {
            pc.printf("Going down...\r\n");
            volume += 0x05;
            rot.Set(0);
        }
        pc.printf("Setting volume - %d", volume);
        vs1053.setvolume(volume, volume);        
    } else if (state == IDLE || state == PAUSED) {
        if (val > 1) {
            pc.printf("forward\n\r");
            current->up();      
            rot.Set(0);
        } else if (val < -1) {
            pc.printf("back\n\r");
            current->down();
            rot.Set(0);
        }
    }
}

void drawNowPlaying(char* playtime) {
    if (strcmp(playtime, lastPlaytime) != 0) {
        lcd.cls();
        lcd.printf("Playing:");
        lcd.locate(11, 0);
        lcd.printf(playtime);
        lcd.locate(0, 1);
        lcd.printf(currentfile);
        strcpy(lastPlaytime, playtime);
    }
}

void checkCued() {
    if (state == CUED) {
        pc.printf("Opening file %s\n\r", currentfile);
        unsigned char buff[BUFFER_SIZE];
        char abs[16];
        strcpy(abs, "/sd/");
        strcat(abs, currentfile);
        FILE *song = fopen(abs, "r");
        if (song == NULL) {
            pc.printf("Cannot find file\n\r");
            lcd.cls();
            lcd.printf("File not found.");
            wait(1.5);
            root.enter();
        } else {
            char* playtime = (char*) malloc(6);
            pc.printf("File open\n\r");
            drawNowPlaying("00:00");
            state = PLAYING;
            while(!feof(song)) {
                if (state == IDLE) {
                    // empty the buffer on the VS1053 then break out of the loop
                    // TODO add cancel play methos to vs1053 lib
                    break;
                } else if (state == PLAYING) {
                    fread(&buff, 1, BUFFER_SIZE, song);
                    int i= 0;
                    while (i < BUFFER_SIZE) {
                        vs1053.writedata(buff[i++]);
                        if (i % MAX_BUF_WRITE == 0) {
                            bool checkPlaytime = true;
                            while (!vs1053.checkdreq()) {
                                if (checkPlaytime) {
                                    vs1053.getplaytime(playtime);
                                    playtime[5] = NULL;
                                    drawNowPlaying(playtime);
                                    checkPlaytime = false;
                                }
                            }
                        }
                    }
                }
            }
            fclose(song);
            vs1053.resetplaytime();
            state = IDLE;
            root.enter();
        }
    }
}

int main() {
    lcd.printf("Initialising...");
    lcd.locate(0, 1);
    lcd.printf("O pod v0.1");
    wait(1.0);
    pc.printf("Starting...\n\r");
    vs1053.init();
    vs1053.loadpatch();
    rot.Set(0);
    rot.attachSW(&buttonPress);
    //rot.attachSWHeld(&buttonHeld);
    rot.attachROT(&control);
    setupMenu();
    while (1) {
        checkCued();
    }
}