Read an wav file from sdcard and play it through I2S on LPC4088 QSB platform

Dependencies:   EALib I2SSlave TLV320 mbed

Fork of playback by Daniel Worrall

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
}