This program utilizes an LCD, RPG, 8 ohm speaker, and SD card to provide the basic functions of a music player. The project cycles through the SD card for .wav files and tracks elapsed time. See http://mbed.org/users/rsartin3/notebook/audio-player/ for more information.
Dependencies: DebounceIn RPG SDFileSystem TextLCD mbed wav_header wave_player
main.cpp
- Committer:
- rsartin3
- Date:
- 2013-03-04
- Revision:
- 0:040129c3d961
- Child:
- 1:f31b40073d35
File content as of revision 0:040129c3d961:
/* MUSIC PLAYER HOORAY wumbo */ #include "mbed.h" #include "DebounceIn.h" #include "SDFileSystem.h" #include "wave_player.h" #include "TextLCD.h" #include "RPG.h" #include "Wav_Support_File.h" #include "string" // Debug mode on: 1 #define DEBUG 0 // -- Debug I/O -- DigitalOut myled(LED1); DigitalOut myled2(LED2); DigitalOut myled3(LED3); DigitalOut myled4(LED4); Serial pc(USBTX, USBRX); // -- RPG I/O -- RPG rpg(p17, p16, p19); // -- Text LCD I/O -- TextLCD lcd(p25, p26, p27, p28, p29, p30); // rs, e, d4-d7 // -- SD card I/O -- SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board DigitalIn sdDetect(p9); // Grounded if no card is inserted, Requires pull up // -- Wave Player I/O -- AnalogOut DACout(p18); wave_player waver(&DACout); // Timer Junk Ticker songTick; time_t time_i; struct playlist { // Doubly-linked list to easily traverse between filenames char s_name[30]; // File name without .wav extension playlist *prev; // Pointer to next filename playlist *next; // Pointer to previous filename }; // Structure name courtesy of Layla Marshall void insert( struct playlist *root, string songName) { /* Insert Put a new songname at the end of the linked list @param *head: Pointer to root node of playlist @param songName: String holding the song name to be inserted */ playlist *new1=(playlist *) malloc(sizeof(playlist)); // Create new playlist node playlist *temp = root; // Start at root node while(temp -> next != NULL) { temp = temp -> next; // Traverse playlist until at last node } strcpy(new1 -> s_name, songName.c_str()); // Copy song name into the file name of the node new1 -> next = NULL; // Set next pointer as null new1 -> prev = temp; // Set previous pointer to the last mode temp -> next = new1; // Hhave last node point to newly created node }; int createPlaylist(const char *location, playlist *root) { /* createPlaylist Read from given directory and if a file has a .wav extension, add it to the playlist. Output the number of songs added to playlist @param *location: Location to look for .wav files, tested for base SD card directory "/sd/" @param *root: Pointer to root of a playlist. The playlist should be empty except for the root node which will be overwritten @out count: Outputs the number of songs added to the playlist */ DIR *d; // Directory pointer dirent *file; // dirent to get file name // playlist *curr = root; // int count = 0; // count of songs added to playlist if(DEBUG) pc.printf("\n\rWell... Let's get started!\r\n"); if((d = opendir(location)) == NULL) { //Attempt to open directory at given location // If Error lcd.cls(); lcd.printf("Unable to open directory!"); if(DEBUG) pc.printf("[!] Unable to open directory\r\n"); }else{ // If Successful while((file = readdir(d)) !=NULL) { // While able to read files in directory if(DEBUG) pc.printf("Parsing file: %s\n\r", file->d_name); string str(file->d_name); // Parse filename size_t exten = str.find_last_of("."); // Find final '.' if(DEBUG) pc.printf("path: %s\n\r", (str.substr(0,exten)).c_str()); // Prints everything before final '.' if(DEBUG) pc.printf("file: %s\n\r", (str.substr(exten+1)).c_str()); // Prints everything after final '.' // If the extension is wav or WAV, add to playlist. Otherwise read in next file if((str.substr(exten+1)).compare("wav") == 0 || (str.substr(exten+1)).compare("WAV") == 0 ){ if(DEBUG) pc.printf("This is a file that I like very much!\r\n"); if(count == 0){ // If still at root node count++; // Increment count strcpy(root->s_name, (str.substr(0,exten)).c_str()); //Copy filename into root node // curr = root; }else{ count++; // Increment count insert(root,str.substr(0,exten)); // Add new song to playlist } } } closedir(d); // Close directory } return count; //Return number of songnames added to playlist } void printList(playlist *root) { /* printList (DEBUG function) Traverses the playlist and writes all songnames to the pc @param *root: pointer to playlist to print */ int count = 1; // Track number, starts at 1 struct playlist *curr = root; // playlist node used to traverse playlist pc.printf("\n\rPrinting File Names:\n\r"); pc.printf("Track #%d: %s\n\r", count, curr->s_name); //Root node song name while(curr -> next != NULL) { // While there is a following node... curr = curr -> next; // Move to it count++; // Increment song count pc.printf("Track #%d: %s\n\r", count, curr->s_name); // And print the current song name } } void freeList(playlist ** root) { /* freeList * Deallocate playlist structure memory, including root node * Sets root pointer to NULL so old memory location cannot be accessed * usage: freeList(&root); */ playlist * node = *root; playlist * temp; if(node == NULL) return; // Protect against an empty root node (no playlist) while(node != NULL) { temp = node->next; free(node); node = temp; } *root = NULL; } void deleteList(playlist * root) { /* deleteList * Deallocates all non-root playlist structures, leaving the root * node with a default "No wavefile" string and null'ed pointers */ if(root == NULL) return; freeList(&(root->next)); root->next = NULL; root->prev = NULL; strcpy(root->s_name, "No wavefile"); } void songClock() { time_t time_f; time_f = time(NULL); // if(DEBUG) printf("Time Elapsed: %d. (Start: %d, Stop: %d)\n\r", time_f - time_i, time_i, time_f); lcd.locate(6,1); lcd.printf("%d", time_f - time_i + 1); } int main() { // --- Control Variables --- int songCount = 0; // Number of songs in the playlist linked list bool sdInsert = false; bool firstList = false; // Is it first instance of reading from SD card bool playlistExist = false; int rpgTick = 0; // Slow down RPG turning speed const int rpgThresh = 5; FILE *wave_file; string mySongName = "Invalid"; unsigned char wave_array[30]; // --- Debug That Junk --- lcd.printf("Hello World!"); if(DEBUG) pc.printf("Hello World!\n\r"); // --- Initialize Playlist --- struct playlist *root; // Create root node root = (playlist *)malloc(sizeof(struct playlist)); root -> next = NULL; // Only node root -> prev = NULL; strcpy(root->s_name, "No wavefile"); // Put song name as "No wavfile" if(DEBUG) printList(root); struct playlist *curr = root; // Current node for playlist traversal // --- Internal Pull-ups --- sdDetect.mode(PullUp); wait(.001); /* ================================ =========== Start Main Program ============ ================================ */ while(1) { // ------------- No SD Card Detected ------------- // Current bug... When SD card is removed and replaced, stays in not detected loop... or something myled = sdDetect; myled2 = 0; if(!sdDetect) { if(DEBUG) { myled2 = 1 - myled2; wait_ms(50); } sdInsert = false; // Note no card is inserted if(playlistExist){ playlistExist = false; deleteList(root); curr = root; } lcd.cls(); lcd.printf("No SD Card!"); if(DEBUG) pc.printf("No SD card detected! Please insert one\n\r"); } // ------------ SD Card Detected ------------ else { // ---------- Set-up Playlist ---------- if(!sdInsert) { // If first loop after inserting SD card sdInsert = true; songCount = createPlaylist("/sd/", root); // Create playlist from .wav files in "/sd/" playlistExist = true; // A playlist now exists firstList = true; // First time through playlist curr = root; // Put current at root node if(DEBUG) printList(root); lcd.cls(); // Display number of songs found lcd.printf("Songs found: %d", songCount); } // ----------------- Turn RPG Clockwise ----------------- if(rpg.dir() == 1) { // If turned clockwise, see if increment is greater than threshold if(rpgTick < rpgThresh){ rpgTick++; //if not increment and do nothing else if(DEBUG) printf("rpgThresh: %d\r\n", rpgThresh); } else { rpgTick = 0; // Clear rpg counter if(firstList){ // If first time controlling just put display node song name firstList = false; lcd.cls(); lcd.printf("%s", curr->s_name); } else { // Otherwise increment if possible and display song name if(curr -> next != NULL){ curr = curr -> next; lcd.cls(); lcd.printf("%s",curr->s_name); } } } } // ----------------- Turn RPG Counter Clockwise ----------------- else { if(rpg.dir() == -1) { // Check if increment is greater than threshold if(rpgTick < rpgThresh) { rpgTick++; } else { rpgTick = 0; // Clear increment if(!firstList ){ //if on song selection, decrement if possible and displays song name if(curr -> prev != NULL){ curr = curr -> prev; lcd.cls(); lcd.printf("%s",curr->s_name); } } } } } // ----------------- Press RPG Button ----------------- if(rpg.pb()) { // if push button is pressed ... SOMETHING lcd.cls(); lcd.printf("Song playing"); //Check sd card maybes // File location name thing mySongName.erase(); mySongName.append("/sd/"); mySongName.append(curr->s_name); mySongName.append(".wav"); // Open File if(DEBUG) printf("Appended Name: %s\n\r", mySongName.c_str()); wave_file=fopen(mySongName.c_str(),"r"); wave_file_check(wave_array, wave_file); if(DEBUG) printf("Sample Rate: %d\r\n", wave_file_info.samples_per_second); fclose(wave_file); lcd.locate(0,1); lcd.printf("Time: / sec"); lcd.locate(10,1); lcd.printf("%d", (int)(wave_file_info.length_of_file / (wave_file_info.samples_per_second * wave_file_info.number_of_channels * wave_file_info.bytes_per_sample)) ); wave_file=fopen(mySongName.c_str(),"r"); songTick.attach(&songClock, 1.0); set_time(1357020000); time_i = time(NULL); if(DEBUG) printf("Start Song\r\n"); waver.play(wave_file); if(DEBUG) printf("Close Song!\r\n"); fclose(wave_file); songTick.detach(); time_i = 0; lcd.cls(); lcd.printf(curr->s_name); if(DEBUG) printf("Finished mai SONG!\r\n"); } if(DEBUG) printf("rpgTick: %d \r\n",rpgTick); } } }