初级会员
- 积分
- 77
- 金钱
- 77
- 注册时间
- 2016-8-25
- 在线时间
- 26 小时
|
5金钱
我正在做音频信号的采集这一块,在原子STM32F407开发板上做的预演,借用的是录音实验:
1、采样频率设置为48KHz
[mw_shl_code=applescript,true] I2S2_SampleRate_Set(48000); //设置采样率 //16000[/mw_shl_code]
2、FFT
由于FFT采样点数设置为1024,这里采用的是DMA双缓冲接收,因此DMA接收长度设置为512
[mw_shl_code=applescript,true]u8 bufUseFlag1 = 0, bufUseFlag2 = 0;
//录音 I2S_DMA接收中断服务函数.在中断里面写入数据
void rec_i2s_dma_rx_callback(void)
{
u16 bw;
u8 res;
if(rec_sta==0X80)//录音模式
{
if (bufUseFlag1 & bufUseFlag2) {
return ;
}
/* 0:当前目标存储器为存储器 0(使用 DMA_SxM0AR 指针寻址)
1:当前目标存储器为存储器 1(使用 DMA_SxM1AR 指针寻址) */
if(DMA1_Stream3->CR&(1<<19))
{
res=f_write(f_rec,i2srecbuf1,I2S_RX_DMA_BUF_SIZE,(UINT*)&bw);//写入文件
if(res)
{
printf("write error:%d\r\n",res);
}
bufUseFlag1 = 1;
}else
{
res=f_write(f_rec,i2srecbuf2,I2S_RX_DMA_BUF_SIZE,(UINT*)&bw);//写入文件
if(res)
{
printf("write error:%d\r\n",res);
}
bufUseFlag2 = 1;
}
wavsize+=I2S_RX_DMA_BUF_SIZE;
}
}[/mw_shl_code]
FFT处理
[mw_shl_code=applescript,true]//WAV录音
void wav_recorder(void)
{
u8 res;
u8 key;
u8 rval=0;
__WaveHeader *wavhead=0;
DIR recdir; //目录
u8 *pname=0;
u8 timecnt=0; //计时器
u32 recsec=0; //录音时间
arm_cfft_radix4_instance_f32 scfft;
arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);
while(f_opendir(&recdir,"0:/RECORDER"))//打开录音文件夹
{
printf("\r\n没有0:/RECORDER,创建\r\n");
f_mkdir("0:/RECORDER"); //创建该目录
}
i2srecbuf1=mymalloc(SRAMIN,I2S_RX_DMA_BUF_SIZE);//I2S录音内存1申请
i2srecbuf2=mymalloc(SRAMIN,I2S_RX_DMA_BUF_SIZE);//I2S录音内存2申请
f_rec=(FIL *)mymalloc(SRAMIN,sizeof(FIL)); //开辟FIL字节的内存区域
wavhead=(__WaveHeader*)mymalloc(SRAMIN,sizeof(__WaveHeader));//开辟__WaveHeader字节的内存区域
pname=mymalloc(SRAMIN,30); //申请30个字节内存,类似"0:RECORDER/REC00001.wav"
if(!i2srecbuf1||!i2srecbuf2||!f_rec||!wavhead||!pname) {
rval=1;
printf("\r\n录音环境创建失败\r\n");
}
if(rval==0)
{
recoder_enter_rec_mode(); //进入录音模式,此时耳机可以听到咪头采集到的音频
pname[0]=0; //pname没有任何文件名
while(rval==0)
{
u32 i;
if (bufUseFlag1 & bufUseFlag2) {
for(i=0;i<FFT_LENGTH;i++) { //生成信号序列
if (i < I2S_RX_DMA_BUF_SIZE)
fft_inputbuf[2*i] = (float32_t)i2srecbuf1; //生成输入信号实部
else
fft_inputbuf[2*i] = (float32_t)i2srecbuf2[i-I2S_RX_DMA_BUF_SIZE];
fft_inputbuf[2*i+1]=0; //虚部全部为0
}
arm_cfft_radix4_f32(&scfft, fft_inputbuf); //FFT计算(基4)
arm_cmplx_mag_f32(fft_inputbuf, fft_outputbuf, FFT_LENGTH); //把运算结果复数求模得幅值
for(i=0; i<FFT_LENGTH; i++) {
printf("fft_outputbuf[%d]:%f\r\n",i,fft_outputbuf);
}
bufUseFlag1 = 0;
bufUseFlag2 = 0;
}
key=KEY_Scan(0);
switch(key)
{
case KEY2_PRES: //STOP&SAVE
if(rec_sta&0X80)//有录音
{
rec_sta=0; //关闭录音
wavhead->riff.ChunkSize=wavsize+36; //整个文件的大小-8;
wavhead->data.ChunkSize=wavsize; //数据大小
f_lseek(f_rec,0); //偏移到文件头.
f_write(f_rec,(const void*)wavhead,sizeof(__WaveHeader),&bw);//写入头数据
f_close(f_rec);
wavsize=0;
printf("\r\n录音结束,并保存音频文件\r\n");
}
rec_sta=0;
recsec=0;
LED1=1; //关闭DS1
break;
case KEY0_PRES: //REC/PAUSE
if(rec_sta&0X01)//原来是暂停,继续录音
{
rec_sta&=0XFE;//取消暂停
}else if(rec_sta&0X80)//已经在录音了,暂停
{
rec_sta|=0X01; //暂停
}else //还没开始录音
{
printf("\r\n还没开始录音\r\n");
recsec=0;
recoder_new_pathname(pname); //得到新的名字
recoder_wav_init(wavhead); //初始化wav数据
res=f_open(f_rec,(const TCHAR*)pname, FA_CREATE_ALWAYS | FA_WRITE);
if(res) //文件创建失败
{
rec_sta=0; //创建文件失败,不能录音
rval=0XFE; //提示是否存在SD卡
printf("\r\nSD卡内无法打开/创建文件\r\n");
}else
{
res=f_write(f_rec,(const void*)wavhead,sizeof(__WaveHeader),&bw);//写入头数据
recoder_msg_show(0,0);
rec_sta|=0X80; //开始录音
}
}
if(rec_sta&0X01)LED1=0; //提示正在暂停
else LED1=1;
break;
case WKUP_PRES: //播放最近一段录音
if(rec_sta!=0X80)//没有在录音
{
if(pname[0])//如果触摸按键被按下,且pname不为空
{
printf("\r\n播放录音\r\n");
recoder_enter_play_mode(); //进入播放模式
audio_play_song(pname); //播放pname
recoder_enter_rec_mode(); //重新进入录音模式
}
}
break;
}
delay_ms(5);
timecnt++;
if((timecnt%20)==0)LED0=!LED0;//DS0闪烁
if(recsec!=(wavsize/wavhead->fmt.ByteRate)) //录音时间显示
{
LED0=!LED0;//DS0闪烁
recsec=wavsize/wavhead->fmt.ByteRate; //录音时间
recoder_msg_show(recsec,wavhead->fmt.SampleRate*wavhead->fmt.NumOfChannels*wavhead->fmt.BitsPerSample);//显示码率
}
}
}
myfree(SRAMIN,i2srecbuf1); //释放内存
myfree(SRAMIN,i2srecbuf2); //释放内存
myfree(SRAMIN,f_rec); //释放内存
myfree(SRAMIN,wavhead); //释放内存
myfree(SRAMIN,pname); //释放内存
}[/mw_shl_code]
3、疑问
(1)我这样的处理思路对吗?没有学过信号处理,希望大神看到帮忙分析下;
(2)我的本意是提取采集到的音频信号频率,根据音乐的不同频率处理不同的事情,但是我看到网上是这么说的:
采样频率为48000Hz,采样点数为1024,频率被分成了1024份,没分为48000/1024=46.875, 我现在不是很明白,如果每个点的频率都是这么计算,那样我怎么确定那个才是声音的频率呢?
(3)由于原子的音频驱动是通过DMA发送两个魔术字0x00来采集音频的,那样的话:即使没有接入耳机口,也会采集到音频信号,我按照方式二采集,同样会有音频数据,怎么才能代码中区分出接入耳机和没接入耳机的情况呢?
希望大家多多指导!
|
|