Record audio data to a .wav file, complete with header, using the TLV320 CODEC and I2S port

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "SDHCFileSystem.h"
00003 #include "MSCFileSystem.h"
00004 #include "TLV320.h"
00005  
00006 TLV320 audio(p9, p10, 52, p5, p6, p7, p8, p29);         //TLV320 object
00007 SDFileSystem sd(p11, p12, p13, p14, "sd");              //SD Card object
00008 MSCFileSystem msc("usb");                               //USB object
00009 InterruptIn finish(p16);                                //button to stop recording                     
00010 FILE *outfp;                                            //file pointer object
00011 
00012 /* Buffers, pointers and states */
00013 int circularBuffer[4096];    
00014 volatile int writePointer = 0;
00015 volatile int theta = 0;
00016 volatile bool recording = false;
00017 volatile long size = 36;
00018 
00019 /* Record settings */
00020 unsigned int frequency = 8000;                         //sample rate
00021 unsigned short wordWidth = 16;                          //bits per sample per channel
00022 unsigned short channels = 2;                            //number of channels
00023 
00024 /* Function to read content of I2SRXFIFO into circular buffer */
00025 void record(void){ 
00026     audio.read();
00027     circularBuffer[writePointer] = audio.rxBuffer[0];
00028     circularBuffer[++writePointer] = audio.rxBuffer[1];
00029     circularBuffer[++writePointer] = audio.rxBuffer[2];
00030     circularBuffer[++writePointer] = audio.rxBuffer[3];
00031     ++writePointer;
00032     theta += 4;  
00033     if(writePointer > 4094) writePointer = 0;
00034 }
00035 
00036 /*Function to write data from circular buffer to usb storage */
00037 void streamToFile(void){
00038     static volatile int readPointer = 0;
00039     while(recording){
00040         if(theta > 512){                                                // only start writing when there is enough data!
00041             fwrite(&circularBuffer[readPointer], 4, 128, outfp);        //write data in 512 byte chunks, this is
00042             theta -= 128;                                               //the natural usb memory chunk size
00043             readPointer += 128;
00044             if(readPointer > 4094) readPointer = 0; 
00045             size += 512;      
00046         }
00047     }
00048     //Complete file and header details
00049     fseek(outfp, 0, SEEK_END);
00050     for(int k = 0;  k < theta; ++k){
00051         fwrite(&circularBuffer[readPointer], 4, 1, outfp);              //this writes the last of the data
00052         ++readPointer;                                                  //held in the circular buffer to memory
00053         if(readPointer > 4094) readPointer = 0; 
00054         size += 4;       
00055     }
00056     return;
00057 }
00058 
00059 /* Function to stop recording, namely to stop audio interrupts */
00060 void stopRecording(void){
00061     audio.stop();
00062     recording = false;
00063     return;
00064 }
00065 
00066 /* Function to write .wav header */
00067 void startHeader(void){
00068 /* RIFF WAV header
00069  * ---------------
00070  * This is composed of several sub chunks. All strings
00071  * are in big endian form. All numeric data is in little endian form.
00072  * All data to be completed after recording (i.e. data chunk size) is default blank.
00073  */
00074     char blockAlign = (char)channels * (wordWidth/8);
00075     int bps = (int)frequency * blockAlign;
00076     char header[44] = { 0x52, 0x49, 0x46, 0x46,     //'RIFF'
00077                         0x00, 0x00, 0x00, 0x00,     //file size
00078                         0x57, 0x41, 0x56, 0x45,     //'WAVE'
00079        /*sub chunk 1*/  0x66, 0x6d, 0x74, 0x20,     //'fmt '
00080                         0x10, 0x00, 0x00, 0x00,     //subchunk size = 16
00081                         0x01, 0x00, ((char)(channels & 0xff)), 0x00,     //PCM compression code | number of channels - I assume no more than 2 channels
00082                         ((char)((frequency & 0xff)>>0)), ((char)((frequency & 0xff00)>>8)), ((char)((frequency & 0xff0000)>>16)), ((char)((frequency & 0xff000000)>>24)),   //sample rate
00083                         ((char)((bps & 0xff)>>0)), ((char)((bps & 0xff00)>>8)), ((char)((bps & 0xff0000)>>16)), ((char)((bps & 0xff000000)>>24)),     //bit rate
00084                         blockAlign, 0x00, ((char)((wordWidth & 0xff)>>0)), ((char)((wordWidth & 0xff00)>>8)),   //bloack align | wordwidth
00085        /*sub chunk 2*/  0x64, 0x61, 0x74, 0x61,     //'data'
00086                         0x00, 0x00, 0x00, 0x00};    //size of data chunk in bytes
00087      fwrite(header, 1, 44, outfp);                   
00088 }
00089 
00090 /* Function to complete header, once recording finishes */
00091 void completeHeader(void){
00092     fseek(outfp, 4, SEEK_SET);
00093     fputc((int) (0xff & size), outfp);              //All these lines are needed to switch the endianess of the data
00094     fputc((int) ((0xff00 & size) >> 8), outfp);
00095     fputc((int) ((0xff0000 & size) >> 16), outfp);
00096     fputc((int) ((0xff000000 & size) >> 24), outfp);
00097     fseek(outfp, 40, SEEK_SET);
00098     size -= 36;
00099     fputc((int) (0xff & size), outfp);
00100     fputc((int) ((0xff00 & size) >> 8), outfp);
00101     fputc((int) ((0xff0000 & size) >> 16), outfp);
00102     fputc((int) ((0xff000000 & size) >> 24), outfp);
00103 }
00104 
00105 /* Main */
00106 int main(){   
00107     /* Create a file to write to */
00108     outfp = fopen("/usb/rec.wav", "w");
00109     if(outfp == NULL){
00110         perror("Error opening file!");
00111         exit(1);
00112     }
00113     startHeader();                          //write first half of header
00114     audio.power(0x02);                      //power up all TLV320, just not microphone
00115     audio.inputVolume(0.999, 0.999);        //Set input volume to max - I don't like to use 1.0 due to rounding errors
00116     audio.frequency(frequency);             
00117     audio.format(wordWidth, (2-channels));  //note int mode = 2 - channels
00118     audio.attach(&record);                  //attach record function to audio interrupt
00119     finish.rise(&stopRecording);            //attach stop button
00120     for(int j = 0; j < 4096; ++j){
00121         circularBuffer[j] = 0;              //clear circular buffer
00122     }
00123     recording = true;
00124     audio.start(RECEIVE);                   //start recording
00125     streamToFile();                             
00126     completeHeader();                       //once finished recording complete the header
00127     fclose(outfp);                          //and close the file
00128 }