VS1053 audio player with lcd and rotary encoder

Dependencies:   LibMenu PinDetect SDFileSystem TextLCD VS1053lib mRotaryEncoder mbed

Committer:
ollie8
Date:
Tue Jun 18 17:01:22 2013 +0000
Revision:
1:0040f640281c
Parent:
0:389ef088650e
Child:
2:1c751f044ecd
Changed control to use interrupts. Added paused menu.

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