VS1053 audio player with lcd and rotary encoder
Dependencies: LibMenu PinDetect SDFileSystem TextLCD VS1053lib mRotaryEncoder mbed
main.cpp@3:b6bf1e6d9cde, 2013-12-26 (annotated)
- 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?
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 | 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 | } |