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

Dependencies:   mbed

Committer:
d_worrall
Date:
Fri Aug 05 15:00:51 2011 +0000
Revision:
0:e7efc8468066
version 2.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
d_worrall 0:e7efc8468066 1 #include "mbed.h"
d_worrall 0:e7efc8468066 2 #include "SDHCFileSystem.h"
d_worrall 0:e7efc8468066 3 #include "MSCFileSystem.h"
d_worrall 0:e7efc8468066 4 #include "TLV320.h"
d_worrall 0:e7efc8468066 5
d_worrall 0:e7efc8468066 6 TLV320 audio(p9, p10, 52, p5, p6, p7, p8, p29); //TLV320 object
d_worrall 0:e7efc8468066 7 SDFileSystem sd(p11, p12, p13, p14, "sd"); //SD Card object
d_worrall 0:e7efc8468066 8 MSCFileSystem msc("usb"); //USB object
d_worrall 0:e7efc8468066 9 InterruptIn finish(p16); //button to stop recording
d_worrall 0:e7efc8468066 10 FILE *outfp; //file pointer object
d_worrall 0:e7efc8468066 11
d_worrall 0:e7efc8468066 12 /* Buffers, pointers and states */
d_worrall 0:e7efc8468066 13 int circularBuffer[4096];
d_worrall 0:e7efc8468066 14 volatile int writePointer = 0;
d_worrall 0:e7efc8468066 15 volatile int theta = 0;
d_worrall 0:e7efc8468066 16 volatile bool recording = false;
d_worrall 0:e7efc8468066 17 volatile long size = 36;
d_worrall 0:e7efc8468066 18
d_worrall 0:e7efc8468066 19 /* Record settings */
d_worrall 0:e7efc8468066 20 unsigned int frequency = 8000; //sample rate
d_worrall 0:e7efc8468066 21 unsigned short wordWidth = 16; //bits per sample per channel
d_worrall 0:e7efc8468066 22 unsigned short channels = 2; //number of channels
d_worrall 0:e7efc8468066 23
d_worrall 0:e7efc8468066 24 /* Function to read content of I2SRXFIFO into circular buffer */
d_worrall 0:e7efc8468066 25 void record(void){
d_worrall 0:e7efc8468066 26 audio.read();
d_worrall 0:e7efc8468066 27 circularBuffer[writePointer] = audio.rxBuffer[0];
d_worrall 0:e7efc8468066 28 circularBuffer[++writePointer] = audio.rxBuffer[1];
d_worrall 0:e7efc8468066 29 circularBuffer[++writePointer] = audio.rxBuffer[2];
d_worrall 0:e7efc8468066 30 circularBuffer[++writePointer] = audio.rxBuffer[3];
d_worrall 0:e7efc8468066 31 ++writePointer;
d_worrall 0:e7efc8468066 32 theta += 4;
d_worrall 0:e7efc8468066 33 if(writePointer > 4094) writePointer = 0;
d_worrall 0:e7efc8468066 34 }
d_worrall 0:e7efc8468066 35
d_worrall 0:e7efc8468066 36 /*Function to write data from circular buffer to usb storage */
d_worrall 0:e7efc8468066 37 void streamToFile(void){
d_worrall 0:e7efc8468066 38 static volatile int readPointer = 0;
d_worrall 0:e7efc8468066 39 while(recording){
d_worrall 0:e7efc8468066 40 if(theta > 512){ // only start writing when there is enough data!
d_worrall 0:e7efc8468066 41 fwrite(&circularBuffer[readPointer], 4, 128, outfp); //write data in 512 byte chunks, this is
d_worrall 0:e7efc8468066 42 theta -= 128; //the natural usb memory chunk size
d_worrall 0:e7efc8468066 43 readPointer += 128;
d_worrall 0:e7efc8468066 44 if(readPointer > 4094) readPointer = 0;
d_worrall 0:e7efc8468066 45 size += 512;
d_worrall 0:e7efc8468066 46 }
d_worrall 0:e7efc8468066 47 }
d_worrall 0:e7efc8468066 48 //Complete file and header details
d_worrall 0:e7efc8468066 49 fseek(outfp, 0, SEEK_END);
d_worrall 0:e7efc8468066 50 for(int k = 0; k < theta; ++k){
d_worrall 0:e7efc8468066 51 fwrite(&circularBuffer[readPointer], 4, 1, outfp); //this writes the last of the data
d_worrall 0:e7efc8468066 52 ++readPointer; //held in the circular buffer to memory
d_worrall 0:e7efc8468066 53 if(readPointer > 4094) readPointer = 0;
d_worrall 0:e7efc8468066 54 size += 4;
d_worrall 0:e7efc8468066 55 }
d_worrall 0:e7efc8468066 56 return;
d_worrall 0:e7efc8468066 57 }
d_worrall 0:e7efc8468066 58
d_worrall 0:e7efc8468066 59 /* Function to stop recording, namely to stop audio interrupts */
d_worrall 0:e7efc8468066 60 void stopRecording(void){
d_worrall 0:e7efc8468066 61 audio.stop();
d_worrall 0:e7efc8468066 62 recording = false;
d_worrall 0:e7efc8468066 63 return;
d_worrall 0:e7efc8468066 64 }
d_worrall 0:e7efc8468066 65
d_worrall 0:e7efc8468066 66 /* Function to write .wav header */
d_worrall 0:e7efc8468066 67 void startHeader(void){
d_worrall 0:e7efc8468066 68 /* RIFF WAV header
d_worrall 0:e7efc8468066 69 * ---------------
d_worrall 0:e7efc8468066 70 * This is composed of several sub chunks. All strings
d_worrall 0:e7efc8468066 71 * are in big endian form. All numeric data is in little endian form.
d_worrall 0:e7efc8468066 72 * All data to be completed after recording (i.e. data chunk size) is default blank.
d_worrall 0:e7efc8468066 73 */
d_worrall 0:e7efc8468066 74 char blockAlign = (char)channels * (wordWidth/8);
d_worrall 0:e7efc8468066 75 int bps = (int)frequency * blockAlign;
d_worrall 0:e7efc8468066 76 char header[44] = { 0x52, 0x49, 0x46, 0x46, //'RIFF'
d_worrall 0:e7efc8468066 77 0x00, 0x00, 0x00, 0x00, //file size
d_worrall 0:e7efc8468066 78 0x57, 0x41, 0x56, 0x45, //'WAVE'
d_worrall 0:e7efc8468066 79 /*sub chunk 1*/ 0x66, 0x6d, 0x74, 0x20, //'fmt '
d_worrall 0:e7efc8468066 80 0x10, 0x00, 0x00, 0x00, //subchunk size = 16
d_worrall 0:e7efc8468066 81 0x01, 0x00, ((char)(channels & 0xff)), 0x00, //PCM compression code | number of channels - I assume no more than 2 channels
d_worrall 0:e7efc8468066 82 ((char)((frequency & 0xff)>>0)), ((char)((frequency & 0xff00)>>8)), ((char)((frequency & 0xff0000)>>16)), ((char)((frequency & 0xff000000)>>24)), //sample rate
d_worrall 0:e7efc8468066 83 ((char)((bps & 0xff)>>0)), ((char)((bps & 0xff00)>>8)), ((char)((bps & 0xff0000)>>16)), ((char)((bps & 0xff000000)>>24)), //bit rate
d_worrall 0:e7efc8468066 84 blockAlign, 0x00, ((char)((wordWidth & 0xff)>>0)), ((char)((wordWidth & 0xff00)>>8)), //bloack align | wordwidth
d_worrall 0:e7efc8468066 85 /*sub chunk 2*/ 0x64, 0x61, 0x74, 0x61, //'data'
d_worrall 0:e7efc8468066 86 0x00, 0x00, 0x00, 0x00}; //size of data chunk in bytes
d_worrall 0:e7efc8468066 87 fwrite(header, 1, 44, outfp);
d_worrall 0:e7efc8468066 88 }
d_worrall 0:e7efc8468066 89
d_worrall 0:e7efc8468066 90 /* Function to complete header, once recording finishes */
d_worrall 0:e7efc8468066 91 void completeHeader(void){
d_worrall 0:e7efc8468066 92 fseek(outfp, 4, SEEK_SET);
d_worrall 0:e7efc8468066 93 fputc((int) (0xff & size), outfp); //All these lines are needed to switch the endianess of the data
d_worrall 0:e7efc8468066 94 fputc((int) ((0xff00 & size) >> 8), outfp);
d_worrall 0:e7efc8468066 95 fputc((int) ((0xff0000 & size) >> 16), outfp);
d_worrall 0:e7efc8468066 96 fputc((int) ((0xff000000 & size) >> 24), outfp);
d_worrall 0:e7efc8468066 97 fseek(outfp, 40, SEEK_SET);
d_worrall 0:e7efc8468066 98 size -= 36;
d_worrall 0:e7efc8468066 99 fputc((int) (0xff & size), outfp);
d_worrall 0:e7efc8468066 100 fputc((int) ((0xff00 & size) >> 8), outfp);
d_worrall 0:e7efc8468066 101 fputc((int) ((0xff0000 & size) >> 16), outfp);
d_worrall 0:e7efc8468066 102 fputc((int) ((0xff000000 & size) >> 24), outfp);
d_worrall 0:e7efc8468066 103 }
d_worrall 0:e7efc8468066 104
d_worrall 0:e7efc8468066 105 /* Main */
d_worrall 0:e7efc8468066 106 int main(){
d_worrall 0:e7efc8468066 107 /* Create a file to write to */
d_worrall 0:e7efc8468066 108 outfp = fopen("/usb/rec.wav", "w");
d_worrall 0:e7efc8468066 109 if(outfp == NULL){
d_worrall 0:e7efc8468066 110 perror("Error opening file!");
d_worrall 0:e7efc8468066 111 exit(1);
d_worrall 0:e7efc8468066 112 }
d_worrall 0:e7efc8468066 113 startHeader(); //write first half of header
d_worrall 0:e7efc8468066 114 audio.power(0x02); //power up all TLV320, just not microphone
d_worrall 0:e7efc8468066 115 audio.inputVolume(0.999, 0.999); //Set input volume to max - I don't like to use 1.0 due to rounding errors
d_worrall 0:e7efc8468066 116 audio.frequency(frequency);
d_worrall 0:e7efc8468066 117 audio.format(wordWidth, (2-channels)); //note int mode = 2 - channels
d_worrall 0:e7efc8468066 118 audio.attach(&record); //attach record function to audio interrupt
d_worrall 0:e7efc8468066 119 finish.rise(&stopRecording); //attach stop button
d_worrall 0:e7efc8468066 120 for(int j = 0; j < 4096; ++j){
d_worrall 0:e7efc8468066 121 circularBuffer[j] = 0; //clear circular buffer
d_worrall 0:e7efc8468066 122 }
d_worrall 0:e7efc8468066 123 recording = true;
d_worrall 0:e7efc8468066 124 audio.start(RECEIVE); //start recording
d_worrall 0:e7efc8468066 125 streamToFile();
d_worrall 0:e7efc8468066 126 completeHeader(); //once finished recording complete the header
d_worrall 0:e7efc8468066 127 fclose(outfp); //and close the file
d_worrall 0:e7efc8468066 128 }