Daniel Worrall
/
Recorder
Record audio data to a .wav file, complete with header, using the TLV320 CODEC and I2S port
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Fri Jul 15 2022 11:08:43 by 1.7.2