VS1053 audio player with lcd and rotary encoder

Dependencies:   LibMenu PinDetect SDFileSystem TextLCD VS1053lib mRotaryEncoder mbed

Committer:
ollie8
Date:
Thu Dec 26 09:15:01 2013 +0000
Revision:
3:b6bf1e6d9cde
Parent:
2:1c751f044ecd
Check in of VS1053 audio player with lcd

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ollie8 0:389ef088650e 1 #include "mbed.h"
ollie8 0:389ef088650e 2 #include "SDFileSystem.h"
ollie8 0:389ef088650e 3 #include "VLSIcodec.h"
ollie8 0:389ef088650e 4 #include "TextLCD.h"
ollie8 0:389ef088650e 5 #include "Menu.h"
ollie8 1:0040f640281c 6 #include "mRotaryEncoder.h"
ollie8 1:0040f640281c 7
ollie8 1:0040f640281c 8 #define BUFFER_SIZE 512
ollie8 1:0040f640281c 9 #define MAX_BUF_WRITE 32
ollie8 0:389ef088650e 10
ollie8 0:389ef088650e 11 enum PlayState {
ollie8 0:389ef088650e 12 IDLE,
ollie8 0:389ef088650e 13 CUED,
ollie8 0:389ef088650e 14 PLAYING,
ollie8 0:389ef088650e 15 PAUSED
ollie8 0:389ef088650e 16 };
ollie8 0:389ef088650e 17
ollie8 2:1c751f044ecd 18 void select(MenuNode *node);
ollie8 2:1c751f044ecd 19 void enterMenu(Menu *menu);
ollie8 2:1c751f044ecd 20 void enterPausedMenu(Menu *menu);
ollie8 2:1c751f044ecd 21
ollie8 0:389ef088650e 22 TextLCD lcd(p24, p25, p26, p27, p28, p29);
ollie8 0:389ef088650e 23 SDFileSystem sd(p5, p6, p7, p8, "sd");
ollie8 0:389ef088650e 24 // PinName mosi, PinName miso, PinName sclk, PinName cs, PinName dreq, PinName rst, PinName xdcs
ollie8 0:389ef088650e 25 VS1053Codec vs1053(p11, p12, p13, p14, p15, p17, p16);
ollie8 1:0040f640281c 26 mRotaryEncoder rot(p21, p22, p23);
ollie8 0:389ef088650e 27 Serial pc(USBTX, USBRX);
ollie8 0:389ef088650e 28 Menu *current;
ollie8 0:389ef088650e 29 PlayState state = IDLE;
ollie8 0:389ef088650e 30 char* currentfile;
ollie8 1:0040f640281c 31 char* lastPlaytime = (char*) malloc(6);
ollie8 1:0040f640281c 32 unsigned char volume = 0x00;
ollie8 2:1c751f044ecd 33 Menu root(&enterMenu, &select, "ROOT", 5);
ollie8 2:1c751f044ecd 34 Menu pausedMenu(&enterPausedMenu, &select, "PAUSED", 2);
ollie8 0:389ef088650e 35
ollie8 1:0040f640281c 36 void select(MenuNode *node) {
ollie8 0:389ef088650e 37 lcd.cls();
ollie8 1:0040f640281c 38 lcd.printf(node->getName());
ollie8 0:389ef088650e 39 }
ollie8 0:389ef088650e 40
ollie8 1:0040f640281c 41 void cueNode(MenuNode *node) {
ollie8 1:0040f640281c 42 currentfile = node->getName();
ollie8 0:389ef088650e 43 state = CUED;
ollie8 0:389ef088650e 44 }
ollie8 0:389ef088650e 45
ollie8 1:0040f640281c 46 void setVolume(MenuNode *node) {
ollie8 0:389ef088650e 47
ollie8 0:389ef088650e 48 }
ollie8 0:389ef088650e 49
ollie8 1:0040f640281c 50 void setBass(MenuNode *node) {
ollie8 0:389ef088650e 51
ollie8 0:389ef088650e 52 }
ollie8 0:389ef088650e 53
ollie8 1:0040f640281c 54 void setTreble(MenuNode *node) {
ollie8 0:389ef088650e 55
ollie8 0:389ef088650e 56 }
ollie8 0:389ef088650e 57
ollie8 1:0040f640281c 58 void continuePlay(MenuNode *node) {
ollie8 1:0040f640281c 59 state = PLAYING;
ollie8 1:0040f640281c 60 }
ollie8 1:0040f640281c 61
ollie8 1:0040f640281c 62
ollie8 0:389ef088650e 63 void enterMenu(Menu *menu) {
ollie8 0:389ef088650e 64 current = menu;
ollie8 0:389ef088650e 65 }
ollie8 0:389ef088650e 66
ollie8 2:1c751f044ecd 67 void enterPausedMenu(Menu *menu) {
ollie8 2:1c751f044ecd 68 current = menu;
ollie8 2:1c751f044ecd 69 state = PAUSED;
ollie8 2:1c751f044ecd 70 }
ollie8 1:0040f640281c 71
ollie8 1:0040f640281c 72 void cancelPlay(MenuNode *node) {
ollie8 1:0040f640281c 73 state = IDLE;
ollie8 1:0040f640281c 74 root.enter();
ollie8 1:0040f640281c 75 }
ollie8 0:389ef088650e 76
ollie8 0:389ef088650e 77 void buttonPress() {
ollie8 0:389ef088650e 78 switch (state) {
ollie8 0:389ef088650e 79 case IDLE:
ollie8 2:1c751f044ecd 80 case PAUSED:
ollie8 1:0040f640281c 81 current->getSelectedNode().enter();
ollie8 0:389ef088650e 82 break;
ollie8 0:389ef088650e 83 case CUED:
ollie8 0:389ef088650e 84 // do nothing until we start playing;
ollie8 0:389ef088650e 85 break;
ollie8 0:389ef088650e 86 case PLAYING:
ollie8 1:0040f640281c 87 pausedMenu.enter();
ollie8 0:389ef088650e 88 break;
ollie8 0:389ef088650e 89 }
ollie8 0:389ef088650e 90 }
ollie8 0:389ef088650e 91
ollie8 1:0040f640281c 92 void buildLibrary() {
ollie8 0:389ef088650e 93 DIR *d;
ollie8 0:389ef088650e 94 struct dirent *p;
ollie8 0:389ef088650e 95 d = opendir("/sd");
ollie8 0:389ef088650e 96 if (d != NULL) {
ollie8 1:0040f640281c 97 int dircount = 0;
ollie8 0:389ef088650e 98 while ((p = readdir(d)) != NULL) {
ollie8 1:0040f640281c 99 dircount++;
ollie8 1:0040f640281c 100 }
ollie8 1:0040f640281c 101 closedir(d);
ollie8 1:0040f640281c 102 Menu *library = new Menu(&enterMenu, &select, "Library", dircount);
ollie8 1:0040f640281c 103 root.addMenuNode(*library);
ollie8 1:0040f640281c 104 d = opendir("/sd");
ollie8 1:0040f640281c 105 while ((p = readdir(d)) != NULL) {
ollie8 0:389ef088650e 106 char * name = p->d_name;
ollie8 0:389ef088650e 107 if (sizeof(name) > 0) {
ollie8 1:0040f640281c 108 MenuNode *node = new MenuNode(&cueNode, &select, name);
ollie8 1:0040f640281c 109 library->addMenuNode(*node);
ollie8 0:389ef088650e 110 }
ollie8 0:389ef088650e 111 }
ollie8 0:389ef088650e 112 } else {
ollie8 2:1c751f044ecd 113 lcd.printf("Could not open root directory!\n");
ollie8 0:389ef088650e 114 }
ollie8 0:389ef088650e 115 closedir(d);
ollie8 0:389ef088650e 116 }
ollie8 0:389ef088650e 117
ollie8 0:389ef088650e 118 void setupMenu() {
ollie8 0:389ef088650e 119 pc.printf("Building menus...\n\r");
ollie8 1:0040f640281c 120 buildLibrary();
ollie8 0:389ef088650e 121 Menu *settings = new Menu(&enterMenu, &select, "Settings", 3);
ollie8 1:0040f640281c 122 root.addMenuNode(*settings);
ollie8 0:389ef088650e 123 Menu *test = new Menu(&enterMenu, &select, "Test", 2);
ollie8 1:0040f640281c 124 root.addMenuNode(*test);
ollie8 1:0040f640281c 125 MenuNode *volume = new MenuNode(&setVolume, &select, "Volume");
ollie8 1:0040f640281c 126 settings->addMenuNode(*volume);
ollie8 1:0040f640281c 127 MenuNode *bass = new MenuNode(&setBass, &select, "Bass");
ollie8 1:0040f640281c 128 settings->addMenuNode(*bass);
ollie8 1:0040f640281c 129 MenuNode *treble = new MenuNode(&setTreble, &select, "Treble");
ollie8 1:0040f640281c 130 settings->addMenuNode(*treble);
ollie8 1:0040f640281c 131 MenuNode *contPlay = new MenuNode(&continuePlay, &select, "Continue");
ollie8 1:0040f640281c 132 MenuNode *cancPlay = new MenuNode(&cancelPlay, &select, "Cancel");
ollie8 1:0040f640281c 133 pausedMenu.addMenuNode(*contPlay);
ollie8 1:0040f640281c 134 pausedMenu.addMenuNode(*cancPlay);
ollie8 0:389ef088650e 135 root.enter();
ollie8 0:389ef088650e 136 pc.printf("Done.\n\r");
ollie8 0:389ef088650e 137 }
ollie8 0:389ef088650e 138
ollie8 1:0040f640281c 139 void control() {
ollie8 1:0040f640281c 140 int val = rot.Get();
ollie8 1:0040f640281c 141 if (state == PLAYING) {
ollie8 1:0040f640281c 142 pc.printf("\r\n");
ollie8 1:0040f640281c 143 if (val > 1) {
ollie8 1:0040f640281c 144 volume -= 0x05;
ollie8 2:1c751f044ecd 145 vs1053.setvolume(volume, volume);
ollie8 1:0040f640281c 146 rot.Set(0);
ollie8 1:0040f640281c 147 } else if (val < -1) {
ollie8 1:0040f640281c 148 volume += 0x05;
ollie8 2:1c751f044ecd 149 vs1053.setvolume(volume, volume);
ollie8 1:0040f640281c 150 rot.Set(0);
ollie8 0:389ef088650e 151 }
ollie8 1:0040f640281c 152 } else if (state == IDLE || state == PAUSED) {
ollie8 1:0040f640281c 153 if (val > 1) {
ollie8 1:0040f640281c 154 current->up();
ollie8 1:0040f640281c 155 rot.Set(0);
ollie8 1:0040f640281c 156 } else if (val < -1) {
ollie8 1:0040f640281c 157 current->down();
ollie8 1:0040f640281c 158 rot.Set(0);
ollie8 1:0040f640281c 159 }
ollie8 1:0040f640281c 160 }
ollie8 1:0040f640281c 161 }
ollie8 1:0040f640281c 162
ollie8 1:0040f640281c 163 void drawNowPlaying(char* playtime) {
ollie8 1:0040f640281c 164 if (strcmp(playtime, lastPlaytime) != 0) {
ollie8 1:0040f640281c 165 lcd.cls();
ollie8 1:0040f640281c 166 lcd.printf("Playing:");
ollie8 1:0040f640281c 167 lcd.locate(11, 0);
ollie8 1:0040f640281c 168 lcd.printf(playtime);
ollie8 1:0040f640281c 169 lcd.locate(0, 1);
ollie8 1:0040f640281c 170 lcd.printf(currentfile);
ollie8 1:0040f640281c 171 strcpy(lastPlaytime, playtime);
ollie8 0:389ef088650e 172 }
ollie8 0:389ef088650e 173 }
ollie8 0:389ef088650e 174
ollie8 0:389ef088650e 175 void checkCued() {
ollie8 0:389ef088650e 176 if (state == CUED) {
ollie8 1:0040f640281c 177 unsigned char buff[BUFFER_SIZE];
ollie8 0:389ef088650e 178 char abs[16];
ollie8 0:389ef088650e 179 strcpy(abs, "/sd/");
ollie8 0:389ef088650e 180 strcat(abs, currentfile);
ollie8 0:389ef088650e 181 FILE *song = fopen(abs, "r");
ollie8 0:389ef088650e 182 if (song == NULL) {
ollie8 0:389ef088650e 183 lcd.cls();
ollie8 0:389ef088650e 184 lcd.printf("File not found.");
ollie8 0:389ef088650e 185 wait(1.5);
ollie8 0:389ef088650e 186 root.enter();
ollie8 0:389ef088650e 187 } else {
ollie8 1:0040f640281c 188 char* playtime = (char*) malloc(6);
ollie8 1:0040f640281c 189 drawNowPlaying("00:00");
ollie8 0:389ef088650e 190 state = PLAYING;
ollie8 0:389ef088650e 191 while(!feof(song)) {
ollie8 0:389ef088650e 192 if (state == IDLE) {
ollie8 0:389ef088650e 193 break;
ollie8 0:389ef088650e 194 } else if (state == PLAYING) {
ollie8 1:0040f640281c 195 fread(&buff, 1, BUFFER_SIZE, song);
ollie8 1:0040f640281c 196 int i= 0;
ollie8 1:0040f640281c 197 while (i < BUFFER_SIZE) {
ollie8 1:0040f640281c 198 vs1053.writedata(buff[i++]);
ollie8 1:0040f640281c 199 if (i % MAX_BUF_WRITE == 0) {
ollie8 1:0040f640281c 200 bool checkPlaytime = true;
ollie8 1:0040f640281c 201 while (!vs1053.checkdreq()) {
ollie8 1:0040f640281c 202 if (checkPlaytime) {
ollie8 1:0040f640281c 203 vs1053.getplaytime(playtime);
ollie8 1:0040f640281c 204 playtime[5] = NULL;
ollie8 1:0040f640281c 205 drawNowPlaying(playtime);
ollie8 1:0040f640281c 206 checkPlaytime = false;
ollie8 1:0040f640281c 207 }
ollie8 1:0040f640281c 208 }
ollie8 0:389ef088650e 209 }
ollie8 0:389ef088650e 210 }
ollie8 0:389ef088650e 211 }
ollie8 0:389ef088650e 212 }
ollie8 0:389ef088650e 213 fclose(song);
ollie8 3:b6bf1e6d9cde 214 vs1053.cancelplayback();
ollie8 1:0040f640281c 215 vs1053.resetplaytime();
ollie8 0:389ef088650e 216 state = IDLE;
ollie8 0:389ef088650e 217 root.enter();
ollie8 0:389ef088650e 218 }
ollie8 0:389ef088650e 219 }
ollie8 0:389ef088650e 220 }
ollie8 0:389ef088650e 221
ollie8 0:389ef088650e 222 int main() {
ollie8 2:1c751f044ecd 223 pc.printf("Starting...\n\r");
ollie8 0:389ef088650e 224 lcd.printf("Initialising...");
ollie8 0:389ef088650e 225 lcd.locate(0, 1);
ollie8 2:1c751f044ecd 226 lcd.printf("O pod v0.2");
ollie8 1:0040f640281c 227 wait(1.0);
ollie8 0:389ef088650e 228 vs1053.init();
ollie8 0:389ef088650e 229 vs1053.loadpatch();
ollie8 1:0040f640281c 230 rot.Set(0);
ollie8 1:0040f640281c 231 rot.attachSW(&buttonPress);
ollie8 1:0040f640281c 232 rot.attachROT(&control);
ollie8 0:389ef088650e 233 setupMenu();
ollie8 0:389ef088650e 234 while (1) {
ollie8 0:389ef088650e 235 checkCued();
ollie8 0:389ef088650e 236 }
ollie8 0:389ef088650e 237 }