VS1053 audio player with lcd and rotary encoder
Dependencies: LibMenu PinDetect SDFileSystem TextLCD VS1053lib mRotaryEncoder mbed
main.cpp@1:0040f640281c, 2013-06-18 (annotated)
- 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?
User | Revision | Line number | New 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 | } |