|  | 
Record ADPCM. 
 
Recording is probably the least straightforward task with vs10xx, though it's not difficult! The main tasks are: 
prepare storage space to save recordingwrite a strictly special kind of RIFF header to start of file Warning:the RIFF header must be of the kind stated in datasheet!
set sampling speed (Clk/256 divider at SPI_AICTRL0)
divider 4 is minimum, giving:
24kHz @ 24.576MHz42kHz with VS1003, 12.288Mhz xtal, clock multiplier 3.5divider 12 gives 8kHz @ 24.576Mhzremember to put the correct sample rate in the RIFF header too!set recording level (gain at SPI_AICTRL1)
this is digital gain, depends on mic signal level
mic/line input impedance is 100 kilo-ohmsfor VS1002, 100...150mVpp signal level gives best resolutionfor VS1003, 50...100mVpp is best for mic, 2Vpp for line in0x1000 is a good first guess for the gain valuevalue 0 sets autogainSPI_VOLUME register controls the loopback volume to earphonesreset vs10xx with ADPCM recording mode bit SM_ADPCM (SPI_MODE.12) set
for vs1003, to select line in instead of mic, set SPI_MODE.14monitor ADPCM_DATA_AVAILABLE level in SPI_HDAT1when data is available, read it into a disksector buffer
data is provided in 256-byte (128-word) blocks
overfilling buffer resets and aligns automatically to block boundarythe fourth byte in a block is always 0x00.check big-endianness / little-endianness for your processorBe relaxed with your timing when reading the SCI registers, give VS10xx a few microseconds time to update the register value after each read. You might need to slower your SPI clock slightly since VS10xx can accept SCI data at slightly faster rate than it is able to provide it.save disksector buffers to diskat end of recording, set SM_OUT_OF_WAV / do a reset of vs10xxinsert correct length information in the RIFF HEADERfinalize diskfile (write FAT records and dir entry) 
 Remarks:in this test version, recording more is entered by pressing the LEFT button while booting and then releasing it after "Filesys OK" message
this version can only record continuous fragments, If a fragment boundary is reached, recording will stop. The main player loop is constructed so that in this situation record() is called again to continue recording to a new file. 
Most MMC handling issues (bugs) seem to be corrected now but the filesystem code might still overwrite files or corrupt FAT tables in some type of MMC card. You are warned, this is beta quality software :)
 
 Todo:VS1002 recording: only new sample rate values need to be calculated. 
 
This recording function can only save data into a continuous area on disk. The Fragment Table fragment[] is used in a special way for recording (to save microcontroller RAM space). fragment[0].start is the first disk sector of the file fragment[0].length will contain the number of disk sectors for the file. 
 Bug:In case of fragmented filesystem, this version will not function properly. 
 
The RIFF header is constructed in a special way (to make life a bit easier). The most proper way to do it would be to take the header "as is" from the datasheet. But to make life a bit easier, the header here is extended to be 512 bytes (a disk sector) long by adding zeroes to the 'fact' chunk. 'junk' chunks should not be used. 
The preliminary header is written to disk prior to recording (to give some chances of recovering track in case of battery failure etc). It has a ridiculously long track length. After recording, the header must be rewritten with correct track length. 
 Todo:second FAT table update
 
Definition at line 101 of file record.c.
 
References AvailableProcessorTime(), Temp::b, DiskBlock::Raw::buf, Temp::c, dataBufPtr, Delay(), diskSect, displayValue, DS_STATIC, fatSectorsPerCluster, fragment, freeSector, GREEN_LED, Temp::i, InitDisplay(), KEY_BUTTON, Address::l, Temp::l, LED_OFF, LED_ON, fragmentEntry::length, Mp3DeselectControl, Mp3ReadRegister(), Mp3Reset(), Mp3WriteRegister, playingState, PS_NEXT_SONG, PS_RECORDING, DiskBlock::raw, ReadDiskSector(), RIFFHeader0, RIFFHeader504, ScanForFreeSector(), sectorAddress, SPI_AICTRL0, SPI_AICTRL1, SPI_CLOCKF, SPI_DECODE_TIME, SPI_HDAT0, SPI_HDAT1, SPI_MODE, fragmentEntry::start, temp, UI_TITLE, uiMode, WriteClusterChain(), and WriteDiskSector().
 
Referenced by main().
 
 00101                       {
00102 
00103   xdata unsigned char  blockNumber;
00104   xdata unsigned long  sectorCount;
00105   xdata unsigned long  lastSector;
00106   bit stopRecording = 0;
00107   bit continueRecording = 0;
00108 
00109   char  oldlevel=0;
00110   blockNumber = 0;
00111   sectorCount = 1;
00112 
00113   playingState  = PS_RECORDING ; 
00114 
00115   
00116 
00117   
00118 #ifdef VS1003 
00119    
00120   Mp3WriteRegister (SPI_CLOCKF,0x66,0x96); 
00121 #else 
00122 Mp3WriteRegister (SPI_CLOCKF,156,204); 
00123 #endif 
00124    
00125   
00126   Mp3WriteRegister (SPI_AICTRL0,0x00,0x09); 
00127   Mp3WriteRegister (SPI_AICTRL1,0x10,0x00); 
00128   Mp3WriteRegister (SPI_MODE,0x18,0x04);    
00129   Delay (10);
00130 
00131   
00132 #ifdef VS1003 
00133    
00134   Mp3WriteRegister (SPI_CLOCKF,0x66,0x96); 
00135 #else 
00136 Mp3WriteRegister (SPI_CLOCKF,156,204); 
00137 #endif 
00138   
00139 
00140   
00151   freeSector  = 0;
00152   ScanForFreeSector ();
00153   sectorAddress .l  = freeSector ;
00154   fragment [0].start  = freeSector ;
00155 
00156 
00164   for  (temp .c =0; temp .c <56; temp .c ++){ 
00165     diskSect .raw .buf [temp .c ] = RIFFHeader0 [temp .c ];
00166   }
00167   for  (temp .i =52; temp .i <504; temp .i ++){
00168     diskSect .raw .buf [temp .i ] = 0;
00169   }
00170   for  (temp .i =504; temp .i <512; temp .i ++){
00171     diskSect .raw .buf [temp .i ] = RIFFHeader504 [temp .i -504];
00172   }
00173 
00180   lastSector = freeSector ;
00181   WriteDiskSector (freeSector);
00182   
00183   
00184   ScanForFreeSector ();
00185   sectorAddress .l  = freeSector ;
00186   dataBufPtr  = diskSect .raw .buf ;
00187   
00188   Delay (10);
00189   
00190   while  (Mp3ReadRegister (SPI_HDAT1)>>8) 
00191     ; 
00192   
00193   dataBufPtr  = diskSect .raw .buf ; 
00194   blockNumber = 0;
00195 
00196   ConsoleWrite("\rRecording, push button to stop..." );
00197   while ((!KEY_BUTTON  
00198         || (blockNumber!=0)
00199         || ((sectorCount)%(fatSectorsPerCluster )!=0))
00200         && (!stopRecording)){  
00201      
00202     GREEN_LED  = LED_ON ;
00203 
00204     
00205     if  (Mp3ReadRegister (SPI_HDAT1) >= 128){ 
00206       
00207       GREEN_LED  = LED_OFF ;
00208       blockNumber++;
00209 
00210       
00211       if  (dataBufPtr >(diskSect .raw .buf +511)){
00212         ConsoleWrite("\rBuffer indexing error. Stop.\r" );
00213         while (1); 
00214       }
00215       
00216       
00217       for  (temp .c =0;temp .c <128;temp .c ++){
00218         data unsigned int  i;
00219         i = Mp3ReadRegister (SPI_HDAT0);         
00220         *dataBufPtr ++ = (i>>8);
00221         *dataBufPtr ++ = (i&0xff);
00222       }
00223       
00224       
00225       { 
00226         
00227         signed int  soundlevel;
00228         
00229         if  (uiMode  == UI_TITLE ){
00230           soundlevel = (signed char )diskSect .raw .buf [1]<<7;
00231           soundlevel |= diskSect .raw .buf [0]>>1;
00232           if  (soundlevel<0) soundlevel = -soundlevel;
00233           displayValue =0;
00234           while  (soundlevel>31){
00235             displayValue ++;         
00236             soundlevel>>=1;
00237           }
00238           if  (soundlevel>19) displayValue ++;
00239           if  (soundlevel>12) displayValue ++;
00240           if  (soundlevel>6) displayValue ++;
00241           displayValue -=3;
00242           displayValue *=13;
00243           if  (oldlevel>displayValue ){
00244             displayValue =oldlevel-3;
00245           }
00246           oldlevel=displayValue ;       
00247         }     
00248         AvailableProcessorTime ();
00249         
00250       }
00251       
00252     }
00253     
00254     
00255     
00256     Mp3DeselectControl ();
00257     
00258     if  (blockNumber==2){ 
00259       
00260       
00261       
00262       
00263       
00264       temp .l  = (sectorCount/8) * 505;
00265       temp .l  /= 1000;
00266       Mp3WriteRegister (SPI_DECODE_TIME,temp .b .b1,temp .b .b0);
00267       Mp3DeselectControl ();
00268 
00269       blockNumber = 0;
00270       sectorCount++;
00271       WriteDiskSector (sectorAddress .l );
00272       lastSector = freeSector ;
00273       ScanForFreeSector (); 
00274       sectorAddress .l  = freeSector ; 
00275       dataBufPtr  = diskSect .raw .buf ; 
00276       if  (freeSector !=(lastSector+1)){ 
00277         stopRecording = 1;
00278         ConsoleWrite("\nFragment end - can't continue recording!\n" );
00279         InitDisplay (DS_STATIC,"FRAGMENT" ," LIMIT!!" ,0);
00280         continueRecording = 1;
00281       }
00282     }
00283     
00284     displayValue  = 0;
00285     
00286   }
00287   fragment [0].length  = sectorCount;
00288   
00289 
00290   
00291   {
00292     xdata addressType  size;
00293 
00294     ReadDiskSector (fragment[0].start);
00295     
00296     
00297     size.l = (sectorCount-1)*1010;
00298     diskSect .raw .buf [48] = size.b.b0;
00299     diskSect .raw .buf [49] = size.b.b1;
00300     diskSect .raw .buf [50] = size.b.b2;
00301     diskSect .raw .buf [51] = size.b.b3;
00302 
00303     
00304     size.l = (sectorCount*512)-8;
00305     diskSect .raw .buf [4] = size.b.b0;
00306     diskSect .raw .buf [5] = size.b.b1;
00307     diskSect .raw .buf [6] = size.b.b2;
00308     diskSect .raw .buf [7] = size.b.b3;
00309 
00310     
00311     size.l = (sectorCount*512)-512;
00312     diskSect .raw .buf [508] = size.b.b0;
00313     diskSect .raw .buf [509] = size.b.b1;
00314     diskSect .raw .buf [510] = size.b.b2;
00315     diskSect .raw .buf [511] = size.b.b3;
00316 
00317     WriteDiskSector (sectorAddress .l );
00318   }
00319 
00320   ConsoleWrite("Registering... FStart:" );
00321   ConsolePutUInt(fragment[0].start);
00322   ConsoleWrite("Registering... Size:" );
00323   ConsolePutUInt(fragment[0].length);
00324   
00325   
00326   fragment [1].start  = 0x0fffffff; 
00327   WriteClusterChain (); 
00328 
00331   sectorAddress .l  = 0; 
00332   
00333   Mp3Reset ();
00334   if  (continueRecording) return PS_RECORDING ;
00335   return PS_NEXT_SONG ;
00336   
00337 }
 
Here is the call graph for this function:   |