上一篇文件保存在SD卡中http://blog.csdn.net/zhangjikuan/article/details/48978627,
项目中要节约成本,只把录音数据放到flash w25x16中WiFi发送
下面是上层程序
#include "recorder.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "led.h"
//#include "lcd.h"
#include "vs10xx.h"
#include "malloc.h"
#include "ff.h"
#include "exfuns.h"
#include "text.h"
#include "flash.h"
#define debugmsg
#define RECORDERADDR (4*1024)
#define DATASIZE 2048
#define READSIZE 1024
//VS1053的WAV录音有bug,这个plugin可以修正这个问题
const u16 wav_plugin[40]=/* Compressed plugin */
{
0x0007, 0x0001, 0x8010, 0x0006, 0x001c, 0x3e12, 0xb817, 0x3e14, /* 0 */
0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, /* 8 */
0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, /* 10 */
0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, /* 18 */
0x9811, 0x0007, 0x0001, 0x8028, 0x0006, 0x0002, 0x2a00, 0x040e,
};
//激活PCM 录音模式
//agc:0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍
void recoder_enter_rec_mode(u16 agc)
{
//如果是IMA ADPCM,采样率计算公式如下:
//采样率=CLKI/256*d;
//假设d=0,并2倍频,外部晶振为12.288M.那么Fc=(2*12288000)/256*6=16Khz
//如果是线性PCM,采样率直接就写采样值
VS_WR_Cmd(SPI_BASS,0x0000);
VS_WR_Cmd(SPI_AICTRL0,8000); //设置采样率,设置为8Khz
VS_WR_Cmd(SPI_AICTRL1,agc); //设置增益,0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍
VS_WR_Cmd(SPI_AICTRL2,0); //设置增益最大值,0,代表最大值65536=64X
VS_WR_Cmd(SPI_AICTRL3,6); //左通道(MIC单声道输入)
VS_WR_Cmd(SPI_CLOCKF,0X2000); //设置VS10XX的时钟,MULT:2倍频;ADD:不允许;CLK:12.288Mhz
VS_WR_Cmd(SPI_MODE,0x1804); //MIC,录音激活
delay_ms(5); //等待至少1.35ms
VS_Load_Patch((u16*)wav_plugin,40);//VS1053的WAV录音需要patch
}
//初始化WAV头.
void recoder_wav_init(__WaveHeader* wavhead) //初始化WAV头
{
wavhead->riff.ChunkID=0X46464952; //"RIFF"
wavhead->riff.ChunkSize=0; //还未确定,最后需要计算
wavhead->riff.Format=0X45564157; //"WAVE"
wavhead->fmt.ChunkID=0X20746D66; //"fmt "
wavhead->fmt.ChunkSize=16; //大小为16个字节
wavhead->fmt.AudioFormat=0X01; //0X01,表示PCM;0X01,表示IMA ADPCM
wavhead->fmt.NumOfChannels=1; //单声道
wavhead->fmt.SampleRate=8000; //8Khz采样率 采样速率
wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*2;//16位,即2个字节
wavhead->fmt.BlockAlign=2; //块大小,2个字节为一个块
wavhead->fmt.BitsPerSample=16; //16位PCM
wavhead->data.ChunkID=0X61746164; //"data"
wavhead->data.ChunkSize=0; //数据大小,还需要计算
}
//显示录音时长
//x,y:地址
//tsec:秒钟数.
void recoder_show_time(u32 tsec)
{
//显示录音时间
printf("TIME:");
printf("%d",tsec/60); //分钟
printf(":");
printf("%d\r\n",tsec%60); //秒钟
}
//通过时间获取文件名
//仅限在SD卡保存,不支持FLASH DISK保存
//组合成:形如"0:RECORDER/REC20120321210633.wav"的文件名
/*
void recoder_new_pathname(u8 *pname)
{
u8 res;
u16 index=0;
while(index<0XFFFF)
{
sprintf((char*)pname,"0:RECORDER/REC%05d.wav",index);
res=f_open(ftemp,(const TCHAR*)pname,FA_READ);//尝试打开这个文件
if(res==FR_NO_FILE)break; //该文件名不存在=正是我们需要的.
index++;
}
}*/
//显示AGC大小
//x,y:坐标
//agc:增益值 1~15,表示1~15倍;0,表示自动增益
void recoder_show_agc(u8 agc)
{
printf("AGC: "); //显示名称,同时清楚上次的显示
if(agc==0)printf("AUTO\r\n"); //自动agc
else printf("%d\r\n",agc); //显示AGC值
}
//播放pname这个wav文件(也可以是MP3等)
u8 rec_play_wav(u8 *pname)
{
u8 rval=0;
u8 *databuf;
u16 i=0,j=0;
u32 sectorsize=0,n=0;
databuf=(u8*)mymalloc(512); //开辟512字节的内存区域
if(databuf==NULL)rval=0XFF ;//内存申请失败.
if(rval==0)
{
VS_HD_Reset(); //硬复位
VS_Soft_Reset(); //软复位
VS_Set_Vol(220); //设置音量
VS_Reset_DecodeTime(); //复位解码时间
VS_SPI_SpeedHigh(); //高速
//读取音频数据总长度,文件总长度-8
SPI_Flash_Read(databuf,RECORDERADDR-44+4,4);
sectorsize+=databuf[3]<<24;
sectorsize+=databuf[2]<<16;
sectorsize+=databuf[1]<<8;
sectorsize+=databuf[0];
sectorsize+=8;//文件数据总长度
while(rval==0)
{
SPI_Flash_Read(databuf,RECORDERADDR-44+n*512,512);
//printf("sectorsize=%d\r\n",n);
i=0;
do//主播放循环
{
if(VS_Send_MusicData(databuf+i)==0)i+=32;//给VS10XX发送音频数据
else //显示播放时间
{
if(j!=VS_Get_DecodeTime())
{
#ifdef debugmsg
recoder_show_time(VS_Get_DecodeTime());
#endif
j=VS_Get_DecodeTime();
LED0=!LED0;//
}
}
}while(i<512);//循环发送1024个字节
n++;
if(n==((sectorsize-44)/512)+1)
{
rval=0;
#ifdef debugmsg
printf("the file size=%dkByte\r\n",sectorsize/1024);
#endif
break;//读完了.
}
}
}
myfree(databuf);
return rval;
}
//录音机
//所有录音文件,均保存在SD卡RECORDER文件夹内.
u8 recoder_play(void)
{
u8 key;
u8 rval=0;
__WaveHeader *wavhead=0;
u16 sectorsize=0;
u8 *recbuf; //数据内存
u16 w;
u16 idx=0;
u8 rec_sta=0; //录音状态
//[7]:0,没有录音;1,有录音;
//[6:1]:保留
//[0]:0,正在录音;1,暂停录音;
u8 *pname=0;
u32 recsec=0; //录音时间
u8 recagc=4; //默认增益为4
u8 playFlag=0; //播放标志
wavhead=(__WaveHeader*)mymalloc(sizeof(__WaveHeader));//开辟__WaveHeader字节的内存区域
if(wavhead==NULL)rval=1;
recbuf=mymalloc(DATASIZE);
if(recbuf==NULL)rval=1;
pname=mymalloc(30); //申请30个字节内存,类似"0:RECORDER/REC00001.wav"
if(pname==NULL)rval=1;
if(rval==0) //内存申请OK
{
#ifdef debugmsg
recoder_show_time(recsec); //显示时间
recoder_show_agc(recagc); //显示agc
#endif
pname[0]=0; //pname没有任何文件名
while(rval==0)
{
key=KEY_Scan(0);
switch(key)
{
case KEY0_PRES: //STOP&SAVE
#ifdef debugmsg
printf("key0:stop/save is down\r\n");
#endif
if(rec_sta&0X80)//有录音
{
wavhead->riff.ChunkSize=sectorsize*DATASIZE+36; //整个文件的大小-8;
wavhead->data.ChunkSize=sectorsize*DATASIZE; //数据大小
SPI_Flash_Write((u8*)wavhead,RECORDERADDR-44,sizeof(__WaveHeader));//写入头数据 44Byte
#ifdef debugmsg
printf("save file in flash ok!all file size=%dkByte\r\n",(sectorsize*DATASIZE+44)/1024);
#endif
sectorsize=0;
}
rec_sta=0;
LED1=1; //关闭DS1
#ifdef debugmsg
recoder_show_time(recsec); //显示时间
#endif
recsec=0;
break;
case KEY1_PRES: //REC/PAUSE
#ifdef debugmsg
//printf("key1:rec is down\r\n");
#endif
if(rec_sta&0X01)//原来是暂停,继续录音
{
//rec_sta&=0XFE;//取消暂停
}else if(rec_sta&0X80)//已经在录音了,暂停
{
//rec_sta|=0X01; //暂停
}else //还没开始录音
{
recoder_enter_rec_mode(1024*recagc);
while(VS_RD_Reg(SPI_HDAT1)>>8); //等到buf 较为空闲再开始
rec_sta|=0X80; //开始录音
recoder_wav_init(wavhead); //初始化wav数据
}
break;
case WKUP_PRES://播放录音(仅在非录音状态下有效)
#ifdef debugmsg
printf("wk_up:play is down\r\n");
#endif
if(rec_sta==0)playFlag=1;
LED1=1;
break;
}
///
//读取数据
if(rec_sta==0X80)//已经在录音了
{
w=VS_RD_Reg(SPI_HDAT1);//看缓冲区中有多少个16位数据
if((w>=768)&&(w<896))//SPI_HDAT0是一个1024个16位数据的缓冲区,也就是2048字节,由于下面读取字节要耗时,边读取的同时
{ //vs1053还是会把数据放入缓冲区,所以当缓冲区中有768*2字节的数据时开始读取1024*2个字节,不准确读写
idx=0; //音频做到差不多就行,不需要那么的精确
while(idx<DATASIZE) //为什么是768?因为读完后还要存储Flash后再循环过来读取一次,存储Flash耗时较长,所以每次存储后容易丢失数据,因此尽量减少存储次数
{ //所以说存储完要赶紧翻过头来读取数据,不然就会发生溢出数据清零,所以程序扫描过程中的printf对音频影响也很大
w=VS_RD_Reg(SPI_HDAT0);
recbuf[idx++]=w&0XFF;
recbuf[idx++]=w>>8;
}
if(sectorsize<=2048*2/DATASIZE*512)//flash未满
{
SPI_Flash_Write(recbuf,RECORDERADDR+sectorsize*DATASIZE,DATASIZE);
sectorsize++;//扇区数增加1,约为16ms
//printf("sectorsize=%d\r\n",sectorsize);
}
else
{
sectorsize=2048*2/DATASIZE*512;
printf("err:flash is all,sectorsize=%d\r\n",sectorsize);
}
}
}else//没有开始录音,按KEY0播放音频
{
if(playFlag)
{
#ifdef debugmsg
printf("开始播放:\r\n");
#endif
rec_play_wav(pname); //播放pname
#ifdef debugmsg
recoder_show_time(recsec); //显示时间
recoder_show_agc(recagc); //显示agc
#endif
playFlag = 0;
}
LED1=0;//DS1长亮
LED0=1;
}
/
if(recsec!=(sectorsize*16/125))//录音时间显示
{
LED1=!LED1;//DS1闪烁
recsec=sectorsize*16/125;
#ifdef debugmsg
recoder_show_time(recsec);//显示时间
#endif
}
}
}
myfree(wavhead);
myfree(recbuf);
myfree(pname);
return rval;
}