VS1053 audio player with lcd and rotary encoder

Dependencies:   LibMenu PinDetect SDFileSystem TextLCD VS1053lib mRotaryEncoder mbed

main.cpp

Committer:
ollie8
Date:
2013-12-26
Revision:
3:b6bf1e6d9cde
Parent:
2:1c751f044ecd

File content as of revision 3:b6bf1e6d9cde:

#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
};

void select(MenuNode *node);
void enterMenu(Menu *menu);
void enterPausedMenu(Menu *menu);

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;
Menu root(&enterMenu, &select, "ROOT", 5);
Menu pausedMenu(&enterPausedMenu, &select, "PAUSED", 2);

void select(MenuNode *node) {
    lcd.cls();
    lcd.printf(node->getName());
}

void cueNode(MenuNode *node) {
    currentfile = node->getName();
    state = CUED;
}

void setVolume(MenuNode *node) {

}

void setBass(MenuNode *node) {
 
}

void setTreble(MenuNode *node) {

}

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


void enterMenu(Menu *menu) {
    current = menu;
}

void enterPausedMenu(Menu *menu) {
    current = menu;
    state = PAUSED;
}

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

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

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) {
            char * name = p->d_name;
            if (sizeof(name) > 0) {
                MenuNode *node = new MenuNode(&cueNode, &select, name);
                library->addMenuNode(*node);
            }
        }
    } else {
        lcd.printf("Could not open root directory!\n");
    }
    closedir(d);
}

void setupMenu() {
    pc.printf("Building menus...\n\r");
    buildLibrary();
    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);
    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();
    if (state == PLAYING) {
        pc.printf("\r\n");
        if (val > 1) {
            volume -= 0x05;
            vs1053.setvolume(volume, volume);        
            rot.Set(0);
        } else if (val < -1) {
            volume += 0x05;
            vs1053.setvolume(volume, volume);        
            rot.Set(0);
        }
    } else if (state == IDLE || state == PAUSED) {
        if (val > 1) {
            current->up();      
            rot.Set(0);
        } else if (val < -1) {
            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) {
        unsigned char buff[BUFFER_SIZE];
        char abs[16];
        strcpy(abs, "/sd/");
        strcat(abs, currentfile);
        FILE *song = fopen(abs, "r");
        if (song == NULL) {
            lcd.cls();
            lcd.printf("File not found.");
            wait(1.5);
            root.enter();
        } else {
            char* playtime = (char*) malloc(6);
            drawNowPlaying("00:00");
            state = PLAYING;
            while(!feof(song)) {
                if (state == IDLE) {
                    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.cancelplayback();
            vs1053.resetplaytime();
            state = IDLE;
            root.enter();
        }
    }
}

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