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

main.cpp

Committer:
rsartin3
Date:
2013-03-05
Revision:
1:f31b40073d35
Parent:
0:040129c3d961
Child:
2:d9953793444c

File content as of revision 1:f31b40073d35:

/*
 * Audio Player
 */

#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);

// Ticker for interrupting song
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
};

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);
        }
    }
}