STM32F4---单声道录音和播放问题

由于是刚开始学习这个东西,对很多地方都不是很了解,便记录一下自己遇到的问题。
这次是单声道的录音和播放问题。
由于给的例程(音乐播放器实验和录音实验)是双声道的,所以要修改一些东西。

原始问题:

在音乐播放器实验中,要是在SD卡中放单声道16khz的wav文件,电脑上放没有问题,但到了开发板上播放速度会加快一倍,听起来十分怪异。但如果放双声道的音频,就播放正常了。
在录音实验中,录音和播放的都是双声道的音频。

解决方法(这里直接对录音机实验的代码进行修改):

第一步:

首先在recorder.c中修改以下这个函数:
第一步
这个应该很多人都能解决,毕竟很容易就能找到。但是呢,仅仅修改这里还远远不够,只修改这里你会发现,录音在开发板上播放没有什么问题,但是到了电脑上,速度会变慢一倍,十分鬼畜。所以还要进行下面的修改。

第二步:

经过第一步发现,很明显数据是有问题的,很可能要修改wm8978,i2s的底层代码,想想都恐怖,于是便想着能不能在recorder.c中修改。另外我问了一下淘宝客服:
淘宝
很明显对于一个新入手的小白来说,还是啥都不知道,甚至我连MONO都不知道是啥,后来才知道是指单声道。
经过查资料,最后采用了他最后的建议。
意思是说,即使经过第一步修改,我们采集到的音频数据还是双声道的数据,如果我们不修改底层的什么wm8978和i2s的代码,我们采取的方法就是把双声道的数据变为单声道,即只取左声道的数据,丢弃右声道。
所以将rec_i2s_dma_rx_callback(void)函数修改为如下:
//¼Òô I2S_DMA½ÓÊÕÖжϷþÎñº¯Êý.ÔÚÖжÏÀïÃæдÈëÊý¾Ý
void rec_i2s_dma_rx_callback(void) 
{    
    u16 bw;
    u8 res;
    u16 i;
    if(rec_sta==0X80)//¼Òôģʽ
    {  
        if(DMA1_Stream3->CR&(1<<19))
        {
            for(i=2;i
汉字有乱码不影响,这个函数调用中断,从i2srecbuf1和i2srecbuf2中录音得到的数据保存到f_rec中,保存数据大小为I2S_RX_DMA_BUF_SIZE/2。
由于两个缓冲区的数据(也就是录音得到的数据)是双声道,形式是 : 【两个字节左声道 两个字节右声道 两个字节左声道 两个字节右声道。。。【
所以我们只需要左声道的数据,于是便有了我们增加的代码:
for(i=2;i
这个循环就是将【左声道数据 右声道数据 左声道数据 右声道数据。。。】变为【左声道数据 左声道数据。。。】把右声道数据全部扔掉,所以我们执行f_write时,长度应该是I2S_RX_DMA_BUF_SIZE/2,即变为一半。
经过这样的修改,录音是没有问题了,录制的音频在电脑上播放时正常的。

第三步:

经过前两步,录制的音频没有什么问题了,但是在开发板上速度会变快,就像音频播放器实验一样,播放速度会加快一倍。这样我们就知道,音频播放也出现了问题!
所以我们修改wavplay.c代码,修改wav_buffill函数:
u32 wav_buffill(u8 *buf,u16 size,u8 bits)
{
    u16 readlen=0;
    u32 bread;
    u16 i;
    u8 *p;
    if(bits==24)//24bitÒôƵ,ÐèÒª´¦ÀíÒ»ÏÂ
    {
        readlen=(size/4)*3;                         //´Ë´ÎÒª¶ÁÈ¡µÄ×Ö½ÚÊý
        f_read(audiodev.file,audiodev.tbuf,readlen,(UINT*)&bread);  //¶ÁÈ¡Êý¾Ý
        p=audiodev.tbuf;
        for(i=0;i
这个函数是将audiodev.file指向的音频文件数据读取到一个buf里面(这里是audiodev.tbuf),数据大小为readlen,也就是输入参数中size的一半。
实际上我们只修改了else里面的代码,因为我们用的16bits数据:
else 
    {
        readlen=size/2;
        f_read(audiodev.file,audiodev.tbuf,readlen,(UINT*)&bread);//16bitÒôƵ,Ö±½Ó¶ÁÈ¡Êý¾Ý  
        p=audiodev.tbuf;
        for(i=0;i
这个意思就是说,这个音频是单声道的,我们得把数据扩充到双声道,这就和第二步的操作相反了(因为wm8978和i2s设置的是双声道,如果不改wm8978.c和i2s.c这俩底层代码的话,只能这样改了,这也是淘宝技术客服最后的建议,把单声道扩展成双声道)。for就是执行的扩充操作。
另外由于这里buf(也就是i2sbuf1或者i2sbuf2)的长度是tbuf的二倍,所以我们要在u8 wav_play_song(u8* fname)函数里进行分配内存的修改,修改如下:
audiodev.i2sbuf1=mymalloc(SRAMIN,WAV_I2S_TX_DMA_BUFSIZE*2);
    audiodev.i2sbuf2=mymalloc(SRAMIN,WAV_I2S_TX_DMA_BUFSIZE*2);
    audiodev.tbuf=mymalloc(SRAMIN,WAV_I2S_TX_DMA_BUFSIZE);
这样的话就大功告成了,无论是录音实验的播放,还是音频播放器实验的播放,播放单声道的数据都没有问题了。

第四步

其实这时候发现LCD显示的录制时间,和播放时的总时间有问题,扩大了二倍,这也是我们前几步修改数据造成的,所以将时间除以二就行了。

在recorder.c中:

if(recsec!=(wavsize/wavhead->fmt.ByteRate)) //¼Òôʱ¼äÏÔʾ
            {      
                LED0=!LED0;//DS0ÉÁ˸ 
                recsec=wavsize/wavhead->fmt.ByteRate;   //¼Òôʱ¼ä
                recsec=recsec/2;
                recoder_msg_show(recsec,wavhead->fmt.SampleRate*wavhead->fmt.NumOfChannels*wavhead->fmt.BitsPerSample);//ÏÔʾÂëÂÊ
            }
在wavplay.c中:
wav_get_curtime(audiodev.file,&wavctrl);//µÃµ½×Üʱ¼äºÍµ±Ç°²¥·ÅµÄʱ¼ä 
                        audio_msg_show((wavctrl.totsec)/2,wavctrl.cursec,wavctrl.bitrate);

至此,问题就全部解决了。这里只是修改了recorder.c和wavplay.c文件,相比较而言是最高层的文件,当然有其他修改方法欢迎大家来分享。

你可能感兴趣的:(STM32F4---单声道录音和播放问题)