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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * Audio Player
00003  * Josh Dunn & Ryan Sartin
00004  */
00005 
00006 #include "mbed.h"
00007 #include "DebounceIn.h"
00008 #include "SDFileSystem.h"
00009 #include "wave_player.h"
00010 #include "TextLCD.h"
00011 #include "RPG.h"
00012 #include "Wav_Support_File.h"
00013 #include "string"
00014 
00015 // Debug mode on: 1
00016 #define DEBUG 0
00017 
00018 // -- Debug I/O --
00019 DigitalOut myled(LED1);
00020 DigitalOut myled2(LED2);
00021 DigitalOut myled3(LED3);
00022 DigitalOut myled4(LED4);
00023 Serial pc(USBTX, USBRX);
00024 
00025 // -- RPG I/O --
00026 RPG rpg(p17, p16, p19);
00027 
00028 // -- Text LCD I/O --
00029 TextLCD lcd(p25, p26, p27, p28, p29, p30); // rs, e, d4-d7
00030 
00031 // -- SD card I/O --
00032 SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board
00033 DigitalIn sdDetect(p9); // Grounded if no card is inserted, Requires pull up
00034 
00035 // -- Wave Player I/O --
00036 AnalogOut DACout(p18);
00037 wave_player waver(&DACout);
00038 
00039 // Ticker for interrupting song
00040 Ticker songTick;
00041 time_t time_i;
00042 
00043 struct playlist { 
00044         // Doubly-linked list to easily traverse between filenames
00045         char s_name[30]; // File name without .wav extension
00046         playlist *prev;  // Pointer to next filename
00047         playlist *next;  // Pointer to previous filename
00048 };
00049 
00050 void insert( struct playlist *root, string songName)
00051 {
00052     /* Insert 
00053        Put a new songname at the end of the linked list
00054        @param *head: Pointer to root node of playlist
00055        @param songName: String holding the song name to be inserted
00056     */ 
00057     playlist *new1=(playlist *) malloc(sizeof(playlist)); // Create new playlist node
00058     playlist *temp = root;      // Start at root node
00059     
00060     while(temp -> next != NULL)
00061     { 
00062         temp = temp -> next; // Traverse playlist until at last node
00063     }
00064     
00065     strcpy(new1 -> s_name, songName.c_str()); // Copy song name into the file name of the node
00066     new1 -> next = NULL;                      // Set next pointer as null
00067     new1 -> prev = temp;                      // Set previous pointer to the last mode
00068     temp -> next = new1;                      // Hhave last node point to newly created node
00069 };
00070 
00071 int createPlaylist(const char *location, playlist *root) {
00072     /* createPlaylist
00073        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
00074        @param *location:    Location to look for .wav files, tested for base SD card directory "/sd/"
00075        @param *root:    Pointer to root of a playlist. The playlist should be empty except for the root node which will be overwritten
00076        @out count:  Outputs the number of songs added to the playlist
00077     */
00078     DIR *d;                 // Directory pointer
00079     dirent *file;           // dirent to get file name
00080     // playlist *curr = root;
00081     int count = 0;          // count of songs added to playlist
00082         
00083     if(DEBUG) pc.printf("\n\rWell... Let's get started!\r\n");
00084     if((d = opendir(location)) == NULL) { // Attempt to open directory at given location
00085         // If Error
00086         lcd.cls();
00087         lcd.printf("Unable to open directory!");
00088         if(DEBUG) pc.printf("[!] Unable to open directory\r\n");
00089     }else{
00090         // If Successful 
00091         while((file = readdir(d)) !=NULL) { // While able to read files in directory
00092             if(DEBUG) pc.printf("Parsing file: %s\n\r", file->d_name);
00093             
00094             string str(file->d_name);               // Parse filename
00095             size_t exten = str.find_last_of(".");   // Find final '.'
00096             
00097             if(DEBUG) pc.printf("path: %s\n\r", (str.substr(0,exten)).c_str()); // Prints everything before final '.'
00098             if(DEBUG) pc.printf("file: %s\n\r", (str.substr(exten+1)).c_str()); // Prints everything after final '.'
00099             
00100             // If the extension is wav or WAV, add to playlist. Otherwise read in next file
00101             if((str.substr(exten+1)).compare("wav") == 0 || (str.substr(exten+1)).compare("WAV") == 0 ){
00102                 if(DEBUG) pc.printf("This is a file that I like very much!\r\n");
00103                 
00104                 if(count == 0){ // If still at root node
00105                     count++;    // Increment count
00106                     strcpy(root->s_name, (str.substr(0,exten)).c_str()); // Copy filename into root node
00107                     // curr = root;
00108                 }else{
00109                     count++;                            // Increment count
00110                     insert(root,str.substr(0,exten));   // Add new song to playlist           
00111                 }
00112             }        
00113         }
00114         closedir(d);    // Close directory
00115     }
00116     return count;       // Return number of songnames added to playlist
00117 }
00118 
00119 void printList(playlist *root) {
00120     /* printList
00121        (DEBUG function) Traverses the playlist and writes all songnames to the pc
00122        @param *root: pointer to playlist to print
00123     */
00124     int count = 1;  // Track number, starts at 1
00125     struct playlist *curr = root;   // playlist node used to traverse playlist
00126     pc.printf("\n\rPrinting File Names:\n\r");          
00127     pc.printf("Track #%d: %s\n\r", count, curr->s_name);    //Root node song name
00128     
00129     while(curr -> next != NULL) {   // While there is a following node...
00130         curr = curr -> next;        // Move to it
00131         count++;                    // Increment song count
00132         pc.printf("Track #%d: %s\n\r", count, curr->s_name); // And print the current song name
00133     }
00134 }
00135 
00136 void freeList(playlist ** root) {
00137 /* freeList
00138  * Deallocate playlist structure memory, including root node
00139  * Sets root pointer to NULL so old memory location cannot be accessed
00140  * usage: freeList(&root);
00141  */ 
00142 
00143 playlist * node = *root;
00144 playlist * temp;
00145 
00146 if(node == NULL)
00147     return; // Protect against an empty root node (no playlist)
00148     
00149     while(node != NULL) {
00150         temp = node->next;
00151         free(node);
00152         node = temp;
00153     } 
00154     *root = NULL;
00155 }
00156 
00157 void deleteList(playlist * root) {
00158 /* deleteList
00159  * Deallocates all non-root playlist structures, leaving the root
00160  * node with a default "No wavefile" string and null'ed pointers
00161  */
00162 
00163 if(root == NULL)
00164     return;
00165         
00166     freeList(&(root->next));
00167     
00168     root->next = NULL;
00169     root->prev = NULL;
00170     strcpy(root->s_name, "No wavefile");
00171 }
00172 
00173 void songClock() {
00174 /*
00175 *   songClock
00176 *   Reads in time and compares it to time_i, the global variable
00177 *   Used with Ticker API to count number of seconds elapsed since song started playing
00178 */
00179     time_t time_f;
00180     time_f = time(NULL);
00181     
00182    // if(DEBUG) printf("Time Elapsed: %d. (Start: %d, Stop: %d)\n\r", time_f - time_i, time_i, time_f);
00183     lcd.locate(6,1);
00184     lcd.printf("%d", time_f - time_i + 1);
00185 }
00186 
00187 int main() {
00188     // --- Control Variables ---
00189     int songCount = 0;  // Number of songs in the playlist linked list
00190     
00191     bool sdInsert = false;
00192     bool firstList = false;   // Is it first instance of reading from SD card
00193     bool playlistExist = false;
00194     
00195     // RPG Variables
00196     int rpgTick = 0; // Slow down RPG turning speed
00197     const int rpgThresh = 5;
00198     
00199     // File interaction variables
00200     FILE *wave_file;    
00201     string mySongName = "Invalid";
00202     unsigned char wave_array[30];    
00203         
00204         
00205     // --- Debug That Junk ---
00206     lcd.printf("Hello World!");
00207     if(DEBUG) pc.printf("Hello World!\n\r");
00208     
00209     // --- Initialize Playlist ---
00210     struct playlist *root; // Create root node
00211     root = (playlist *)malloc(sizeof(struct playlist));
00212     root -> next = NULL;            // Only node
00213     root -> prev = NULL;
00214     strcpy(root->s_name, "No wavefile");    // Put song name as "No wavfile"
00215     if(DEBUG) printList(root);
00216     
00217     struct playlist *curr = root; // Current node for playlist traversal
00218         
00219     // --- Internal Pull-ups --- 
00220     sdDetect.mode(PullUp);
00221     wait(.001);
00222 
00223     /*      ================================
00224     ===========    Start Main Program    ============
00225             ================================
00226     */    
00227     while(1) {
00228         // ------------- No SD Card Detected ------------- 
00229         // Current bug... When SD card is removed and replaced, stays in not detected loop... or something
00230         if(DEBUG) myled = sdDetect; 
00231         if(DEBUG) myled2 = 0;
00232         if(!sdDetect)
00233         {
00234             if(DEBUG) {
00235                 myled2 = 1 - myled2;
00236                 wait_ms(50);
00237             }
00238             sdInsert = false;                   // Note no card is inserted
00239             if(playlistExist){                  // If a playlist has been made
00240                 playlistExist = false;
00241                 deleteList(root);               // Clear playlist
00242                 curr = root;
00243             }
00244             lcd.cls();
00245             lcd.printf("No SD Card!");
00246             if(DEBUG) pc.printf("No SD card detected! Please insert one\n\r");
00247         }
00248         // ------------ SD Card Detected ------------
00249         else {
00250             // ---------- Set-up Playlist ----------   
00251             if(!sdInsert) {
00252                 // If first loop after inserting SD card
00253                 sdInsert = true;
00254                 songCount = createPlaylist("/sd/", root); // Create playlist from .wav files in "/sd/"
00255                 playlistExist = true;                     // A playlist now exists
00256                 firstList = true;                         // First time through playlist
00257                 curr = root;                              // Put current at root node
00258                 if(DEBUG) printList(root);
00259                 lcd.cls();                                // Display number of songs found
00260                 lcd.printf("Songs found: %d", songCount);
00261             }
00262     
00263             // ----------------- Turn RPG Clockwise -----------------
00264             if(rpg.dir() == 1) {
00265                 // If turned clockwise, see if increment is greater than threshold
00266                 if(rpgTick < rpgThresh){
00267                     rpgTick++;  //if not increment and do nothing else
00268                     if(DEBUG) printf("rpgThresh: %d\r\n", rpgThresh);
00269                 } 
00270                 else {
00271                     rpgTick = 0; // Clear rpg counter
00272                     
00273                     if(firstList){  // If first time controlling just put display node song name
00274                         firstList = false;
00275                         lcd.cls();
00276                         lcd.printf("%s", curr->s_name);              
00277                     }
00278                     else {          // Otherwise increment if possible and display song name
00279                         if(curr -> next != NULL){
00280                             curr = curr -> next;
00281                             lcd.cls();
00282                             lcd.printf("%s",curr->s_name);
00283                         }        
00284                     }
00285                 }
00286             }    
00287             // ----------------- Turn RPG Counter Clockwise -----------------        
00288             else { 
00289                 if(rpg.dir() == -1) {
00290                     // Check if increment is greater than threshold
00291                     if(rpgTick < rpgThresh) {
00292                         rpgTick++;
00293                     } 
00294                     else {
00295                         rpgTick = 0;   // Clear increment
00296                         
00297                         if(!firstList ){    //if on song selection, decrement if possible and displays song name
00298                             if(curr -> prev != NULL){
00299                                 curr = curr -> prev;
00300                                 lcd.cls();
00301                                 lcd.printf("%s",curr->s_name);
00302                             }            
00303                         }
00304                     }
00305                 }
00306             }
00307             // ----------------- Press RPG Button -----------------        
00308             if(rpg.pb()) {
00309                 // if push button is pressed:
00310                 lcd.cls();
00311                 lcd.printf("Song playing"); // Inform user song is playing
00312                                 
00313                 // File location name
00314                 mySongName.erase();
00315                 mySongName.append("/sd/"); // ======== Change if not using base sd card location =====
00316                 mySongName.append(curr->s_name); // Add current song name
00317                 mySongName.append(".wav");  // Add .wav extension
00318                 if(DEBUG) printf("Appended Name: %s\n\r", mySongName.c_str());
00319                 
00320                 // Wav file header info 
00321                 wave_file=fopen(mySongName.c_str(),"r");  // Open file to get header information                
00322                 wave_file_check(wave_array, wave_file);   // Put info in global variable
00323                 if(DEBUG) printf("Sample Rate: %d\r\n", wave_file_info.samples_per_second); 
00324                 fclose(wave_file);                        // Close file
00325                 
00326                 // Initialize bottom row of LCD screen
00327                 lcd.locate(0,1);
00328                 lcd.printf("Time:    /   sec");
00329                 lcd.locate(10,1);
00330                 // Print length of selected wavfile
00331                 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)) );
00332                 
00333                 // Open song for playing
00334                 wave_file=fopen(mySongName.c_str(),"r");
00335                 // Start Ticker function that counts time elapsed each second
00336                 songTick.attach(&songClock, 1.0);
00337                 // Set reference time
00338                 set_time(1357020000);
00339                 time_i = time(NULL);
00340                 // Play song
00341                 if(DEBUG) printf("Start Song\r\n");
00342                 waver.play(wave_file);
00343                 // Close file
00344                 if(DEBUG) printf("Close Song!\r\n");
00345                 fclose(wave_file);
00346                 
00347                 // End ticker function
00348                 songTick.detach();
00349                 time_i = 0;
00350                 
00351                 // Clear LCD and show selected wav file
00352                 lcd.cls();
00353                 lcd.printf(curr->s_name);
00354                 if(DEBUG) printf("Finished mai SONG!\r\n");                
00355             }              
00356         }
00357     }
00358 }