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

Files at this revision

API Documentation at this revision

Comitter:
rsartin3
Date:
Mon Mar 04 22:37:29 2013 +0000
Child:
1:f31b40073d35
Commit message:
Working version with clock;

Changed in this revision

DebounceIn.lib Show annotated file Show diff for this revision Revisions of this file
RPG.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
wav_header.lib Show annotated file Show diff for this revision Revisions of this file
wave_player.lib Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebounceIn.lib	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/DebounceIn/#1f3e0982f89d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RPG.lib	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/canderson199/code/RPG/#0b389c2c21b5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/SDFileSystem/#c8f66dc765d4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TextLCD.lib	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/TextLCD/#44f34c09bd37
--- /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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/3d0ef94e36ec
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wav_header.lib	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+wav_header#a50bba1964ec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wave_player.lib	Mon Mar 04 22:37:29 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/sravet/code/wave_player/#acc3e18e77ad