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/wav-player-with-RPG-based-menu/ for more information.

Dependencies:   DebounceIn RPG SDFileSystem TextLCD mbed wav_header wave_player

Fork of Audio_Player by Ryan Sartin

Revision:
0:040129c3d961
Child:
1:f31b40073d35
diff -r 000000000000 -r 040129c3d961 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,351 @@
+/*
+    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);
+        }
+    }
+}