Read an wav file from sdcard and play it through I2S on LPC4088 QSB platform
Dependencies: EALib I2SSlave TLV320 mbed
Fork of playback by
works with 16bits / 44,1 khz files.
I'm going to work on 24/32 bits, 48khz 96 khz files...
main.cpp
- Committer:
- Grag38
- Date:
- 2016-07-23
- Revision:
- 2:ce93bf118649
- Parent:
- 0:3d6892f6384f
File content as of revision 2:ce93bf118649:
#include "mbed.h" #include "TLV320.h" Serial pc(USBTX, USBRX); /****************************************************************************** * Includes *****************************************************************************/ #include "MCIFileSystem.h" /****************************************************************************** * Typedefs and defines *****************************************************************************/ typedef bool (*syncFunc)(const char* name, bool isDir); /****************************************************************************** * Local variables *****************************************************************************/ MCIFileSystem mcifs("mci"); DigitalOut myled1(LED1); DigitalOut myled2(LED2); /****************************************************************************** * Local functions *****************************************************************************/ static void ledShowProgress() { static int state = 0; state = (state + 1) % 2; switch (state) { case 0: myled1 = 1; myled2 = 0; break; case 1: default: myled1 = 0; myled2 = 1; } } static void handleError(const char* msg) { printf(msg); while(true) { myled1 = 1; myled2 = 1; wait(0.3); myled1 = 0; myled2 = 0; wait(0.3); } } static bool recursiveProcessFS(char* buff, const char* name, syncFunc func, bool adding) { uint32_t len = strlen(buff); if (len > 0) { if (buff[len - 1] != '/') { buff[len++] = '/'; buff[len] = '\0'; } } strcat(buff, name); len += strlen(name); if (len > 60) { // ugly fix to avoid crashes that occurs when file name is larger than buffer // in FATFileSystem. printf("skipped: %s\n", buff); return true; } DIR *d = opendir(buff); bool result = true; // success if (d != NULL) { if (adding) { // when processing in adding mode folders must be created before it's content result = func(buff, true); } struct dirent *p; while (result && ((p = readdir(d)) != NULL)) { result = recursiveProcessFS(buff, p->d_name, func, adding); buff[len] = '\0'; } closedir(d); if (result && !adding) { // when processing in removing mode folders must be deleted after it's content result = func(buff, true); } } else { // a file result = func(buff, false); } return result; } static uint32_t fileLen(FILE* f) { uint32_t pos = ftell(f); fseek(f, 0, SEEK_END); uint32_t size = ftell(f); fseek(f, pos, SEEK_SET); return size; } static bool copyFH(FILE* fSrc, FILE* fDst) { char buff[512]; uint32_t left = fileLen(fSrc); uint32_t num; uint32_t chunk; fseek(fSrc, 0, SEEK_SET); do { chunk = (left < 512) ? left : 512; num = fread(buff, 1, chunk, fSrc); if (num > 0) { uint32_t tmp = fwrite(buff, 1, num, fDst); if (tmp != num) { // failed to write return false; } left -= num; ledShowProgress(); } } while(num > 0 && left > 0); // copied entire file return true; } static bool copy(const char* fnameSrc, const char* fnameDest) { FILE* fhSrc = NULL; FILE* fhDest = NULL; bool success = false; do { fhSrc = fopen(fnameSrc, "r"); if (fhSrc == NULL) { break; } fhDest = fopen(fnameDest, "w"); if (fhDest == NULL) { break; } if (!copyFH(fhSrc, fhDest)) { break; } success = true; } while (false); if (fhSrc != NULL) { fclose(fhSrc); } if (fhDest != NULL) { fclose(fhDest); } return success; } static bool list(const char* name, bool isDir) { if (isDir) { printf("d: %s\n", name); } else { FILE* f = fopen(name, "r"); if (f != NULL) { uint32_t len = fileLen(f); printf("f: %7u %s\n", len, name); fclose(f); } else { printf("f: ??? %s\n", name); } } return true; } static void recursiveList(const char* dirname) { printf("\nRecursive list of file and folders in %s\n", dirname); char* buff = (char*)malloc(512); if (buff != NULL) { buff[0] = '\0'; recursiveProcessFS(buff, dirname, list, true); free(buff); } } static void testAppend(const char* filename) { FILE *fp = fopen(filename, "a"); if (fp != NULL) { fprintf(fp, "Hello World!"); fclose(fp); } } /****************************************************************************** * TestSdCard function *****************************************************************************/ int TestSdCard() { printf("\n-----------------\n\nWelcome to the MCI file system example...\n"); if (!mcifs.cardInserted()) { printf("Please insert a SD/MMC card...\n"); while (!mcifs.cardInserted()) { wait(0.5); } printf("Card detected!\n"); } recursiveList("/mci/"); copy("/mci/expanding.txt", "/mci/expanding.old"); testAppend("/mci/expanding.txt"); //recursiveList("/mci/"); printf("Found SD/MMC card, writing to /mci/myfile.txt ...\n"); Timer t; t.start(); FILE *fp = fopen("/mci/myfile.txt", "w"); if (fp != NULL) { for (long i=0; i<100000L; i++) fprintf(fp, "Hello World!\n"); fclose(fp); printf("Wrote to /mci/myfile.txt\n"); } else { printf("Failed to open /mci/myfile.txt\n"); } t.stop(); printf("The time taken was %f seconds\n", t.read()); handleError("Program completed!\n"); return 1; } TLV320 audio(p9, p10, 52, p11, p12, p13, p14, p16); //TLV320 object InterruptIn volumeSet(p17); AnalogIn aIn(p19); FILE *infp; //File pointer object /* Buffers */ int circularBuffer[4096]; volatile int readPointer = 0; volatile int theta = 0; /* Wav file header data, for setting up the transfer protocol */ short channels; long sampleRate; short wordWidth; /* Function to set volume*/ void setVolume(void){ audio.outputVolume(aIn, aIn); } /* Function to read from circular buffer and send data to TLV320 */ void play(void){ audio.write(circularBuffer, readPointer, 8); //Pointer fun :-) readPointer += 8; readPointer &= 0xfff; theta -= 8; } /* Function to load circular buffer from SD Card */ void fillBuffer(void){ while(!feof(infp)){ //fill the circular buffer until the end of the file static volatile int writePointer = 0; if(theta < 4096){ fread(&circularBuffer[writePointer], 4, 4, infp); //read 4 integers into the circular buffer at a time //More pointer fun :D theta+=4; writePointer+=4; writePointer &= 0xfff; } } } /* main */ int main() { pc.baud(460800); infp = fopen("/mci/agnes.wav","rb"); if(infp == NULL){ //make sure it's been opened perror("Error opening file!"); exit(1); } /* Parse wav file header */ fseek(infp, 22, SEEK_SET); fread(&channels, 2, 1, infp); fseek(infp, 24, SEEK_SET); fread(&sampleRate, 4, 1, infp); fseek(infp, 34, SEEK_SET); fread(&wordWidth, 2, 1, infp); volumeSet.rise(&setVolume); //attach set volume function to digital input audio.power(0x07); //power up TLV apart from analogue input audio.frequency(sampleRate); //set sample frequency audio.format(wordWidth, (2-channels)); //set transfer protocol audio.attach(&play); //attach interrupt handler to send data to TLV320 for(int j = 0; j < 4096; ++j){ //upon interrupt generation circularBuffer[j] = 0; //clear circular buffer } audio.start(TRANSMIT); //interrupt come from the I2STXFIFO only fillBuffer(); //continually fill circular buffer }