OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4706|回复: 13

音乐播放单声道文件,怎么搞?求原子哥及各位高能指点。

[复制链接]

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
发表于 2017-1-17 15:35:42 | 显示全部楼层 |阅读模式
5金钱
本帖最后由 tianxin19 于 2017-1-17 15:44 编辑

STM32F407 实验43音乐播放例程
例程里的附带的音频是双声道的,我要播放一个单声道的音乐总是放不出来。原来的代码如下。
[mw_shl_code=c,true]//填充buf
//buf:数据区
//size:填充数据量
//bits:位数(16/24)
//返回值:读到的数据个数
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<size;)
                {
                        buf[i++]=p[1];
                        buf=p[2];
                        i+=2;
                        buf[i++]=p[0];
                        p+=3;
                }
                bread=(bread*4)/3;                //填充后的大小.
        }else
        {
                f_read(audiodev.file,buf,size,(UINT*)&bread);//16bit音频,直接读取数据  
                if(bread<size)//不够数据了,补充0
                {
                        for(i=bread;i<size-bread;i++)buf=0;
                }
        }
        return bread;
}  [/mw_shl_code]

我对代码进行了修改,加入了对声道数的预判,但是效果不对,代码如下:
[mw_shl_code=c,true]//填充buf
//buf:数据区
//size:填充数据量
//bits:位数(16/24)
//返回值:读到的数据个数
u32 wav_buffill(u8 *buf,u16 size,u8 bits,u8 nch)
{
        u16 readlen=0;
        u32 bread;
        u16 i,j;
        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<size;)
                {
                        buf[i++]=p[1];
                        buf=p[2];
                        i+=2;
                        buf[i++]=p[0];
                        p+=3;
                }
                bread=(bread*4)/3;                //填充后的大小.
        }
        else
        {
                if(nch==2)
                {
                        f_read(audiodev.file,buf,size,(UINT*)&bread);//16bit音频,直接读取数据
                        if(bread<size)//不够数据了,补充0
                        {
                                for(i=bread;i<size-bread;i++)buf=0;
                        }               
                }
                else
                {
                        readlen=size/2;
                        f_read(audiodev.file,audiodev.tbuf,readlen,(UINT*)&bread);        //读取数据
                        p=audiodev.tbuf;
                        for(j=0;j<size;j++)
                        {
                                buf[2*j]=p[j];
                                buf[2*j+1]=p[j];
                        }
                        bread=bread/2;
                }
        }
        return bread;
}  [/mw_shl_code]

请原子哥,及各位高能指教!

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-1-17 15:39:36 | 显示全部楼层

RE: 音乐播放单声道文件,怎么搞?求原子哥及各位高能指点。

本帖最后由 tianxin19 于 2017-1-17 15:42 编辑

[mw_shl_code=c,true]//填充buf
//buf:数据区
//size:填充数据量
//bits:位数(16/24)
//返回值:读到的数据个数
u32 wav_buffill(u8 *buf,u16 size,u8 bits,u8 nch)
{
        u16 readlen=0;
        u32 bread;
        u16 i,j;
        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<size;)
                {
                        buf[i++]=p[1];
                        buf=p[2];
                        i+=2;
                        buf[i++]=p[0];
                        p+=3;
                }
                bread=(bread*4)/3;                //填充后的大小.
        }
        else
        {
                if(nch==2)
                {
                        f_read(audiodev.file,buf,size,(UINT*)&bread);//16bit音频,直接读取数据
                        if(bread<size)//不够数据了,补充0
                        {
                                for(i=bread;i<size-bread;i++)buf=0;
                        }               
                }
                else
                {
                        readlen=size/2;
                        f_read(audiodev.file,audiodev.tbuf,readlen,(UINT*)&bread);        //读取数据
                        p=audiodev.tbuf;
                        for(j=0;j<size;j++)
                        {
                                buf[2*j]=p[j];
                                buf[2*j+1]=p[j];
                        }
                        bread=bread/2;
                }
        }
        return bread;
}  [/mw_shl_code]
回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-1-17 17:36:58 | 显示全部楼层
请各位高能帮忙给指点指点。
回复

使用道具 举报

靠谱哥 该用户已被删除
发表于 2017-1-17 18:26:29 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-1-18 09:02:14 | 显示全部楼层
在论坛里看了一些帖子,没有找到解决办法。郁闷中…………
原子哥,各们高能,请伸出你的援助之手。
回复

使用道具 举报

11

主题

1044

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3722
金钱
3722
注册时间
2011-5-23
在线时间
2013 小时
发表于 2017-1-18 09:29:23 | 显示全部楼层
步骤1:先按例程放个双声道的。
RT-Thread RTOS 音频,WIFI,蓝牙
回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-1-18 09:39:14 | 显示全部楼层
按例程播放过双声道的WAVE文件,正常,没有问题。

现在主要是要播放一些单声道的文件,不知道为什么不行。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2017-1-18 10:28:37 | 显示全部楼层
思路其实很简单
将单声道数据扩充到立体声输出就行了

读数据的时候,读取一半,没错,但是你数据处理(填充)的时候,出错了
声音是16位的,你搞个8位的数组在处理,而且没处理好,自然不能正常出声。

仿真一下吧,很好解决的。

仿真看看数据,你就知道哪里错了,比如你读到单声道0XAAFF,填充到立体声后,肯定是0XAAFF AAFF。
你这种处理方式,是无法得到0XAAFF AAFF的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

15

主题

180

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2017-1-18
在线时间
23 小时
发表于 2017-1-18 20:31:40 | 显示全部楼层
同意6楼
回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-1-24 11:39:36 | 显示全部楼层
本帖最后由 tianxin19 于 2017-1-24 12:58 编辑

SD卡内三个WAV文件,分别为:Success.wav 、 Fail.wav、一生所爱.wav等。

有些声频播放不正常,怀疑是SPI频率过快,尝试修改SPI速度设置函数
[mw_shl_code=c,true]SPI1_Init();                                           //初始化SPI
        SPI1_SetSpeed(SPI_SPEED_2);                //设置为42M时钟,高速模式 [/mw_shl_code]


补充内容 (2017-2-3 10:10):
将其修改为SPI_BaudRatePrescaler_256(相当于32K时钟),问题依旧存在。故排除。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2017-1-24 20:31:09 | 显示全部楼层
tianxin19 发表于 2017-1-24 11:39
SD卡内三个WAV文件,分别为:Success.wav 、 Fail.wav、一生所爱.wav等。
有些声频播放不正常,怀疑是SPI ...

这个你SD卡用的SPI 驱动么?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

2

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
68
金钱
68
注册时间
2017-1-29
在线时间
6 小时
发表于 2017-1-29 18:19:56 | 显示全部楼层
Mark一下
回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-2-3 10:13:19 | 显示全部楼层
本帖最后由 tianxin19 于 2017-2-3 13:18 编辑

怀疑采样率解析不正确,对程序进行跟踪调试。
跟踪发现采样率解析正常,而能正常播放的音频是双声道的,单声道的不能正常播放。检查代码发现,在函数wav_buffill()里没有对单声道的情况进行处理。
[mw_shl_code=c,true]//填充buf
//buf:数据区
//size:填充数据量
//bits:位数(16/24)
//返回值:读到的数据个数
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<size;)
                {
                        buf[i++]=p[1];
                        buf=p[2];
                        i+=2;
                        buf[i++]=p[0];
                        p+=3;
                }
                bread=(bread*4)/3;                //填充后的大小.
        }else
        {
                f_read(audiodev.file,buf,size,(UINT*)&bread);//16bit音频,直接读取数据  
                if(bread<size)//不够数据了,补充0
                {
                        for(i=bread;i<size-bread;i++)buf=0;
                }
        }
        return bread;
}  [/mw_shl_code]
依据参考资料显示,在飞利浦(I2S)标准模式下,一个采样周期(1/fs)内,左右声道数据分时传输。那么单声道音频文件,没有右声道的数据,将被强制拆分成左右声道数据输出,所以只能听到杂音。

如何去处理?在论坛里查找了许久我得到了一种思路:对wav_buffill()进行修改,当文件解析到声道数为单声道时,将单声道的数据复制给别一声道,使左右声道输出一样的音频就可以正常播放。

[mw_shl_code=c,true]u32 wav_buffill(u8 *buf,u16 size,u8 bits,u8 nch)
{
        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<size;)
                {
                        buf[i++]=p[1];
                        buf=p[2];
                        i+=2;
                        buf[i++]=p[0];
                        p+=3;
                }
                bread=(bread*4)/3;                //填充后的大小.
        }
        else                        
        {
                if(nch==2)
                {
                        f_read(audiodev.file,buf,size,(UINT*)&bread);//16bit音频,直接读取数据                        
                }
                else        //对单声道的进行扩充

                {
                        readlen=size/2;
                        f_read(audiodev.file,audiodev.tbuf,readlen,(UINT*)&bread);        //读取数据
                        p=audiodev.tbuf;
                        for(i=0;i<readlen;i++)
                        {
                                buf[4*i+0]=p[0];
                                buf[4*i+1]=p[1];
                                buf[4*i+2]=p[0];
                                buf[4*i+3]=p[1];
                                p+=2;
                        }
                        bread=bread*2;
                }
                if(bread<size)//不够数据了,补充0
                {
                        for(i=bread;i<size-bread;i++)buf=0;
                }               
        }
        return bread;
}  [/mw_shl_code]

回复

使用道具 举报

3

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-12-13
在线时间
19 小时
 楼主| 发表于 2017-2-3 10:21:21 | 显示全部楼层
本帖最后由 tianxin19 于 2017-2-3 10:27 编辑

再次进行测试,依然不能播放。仔细检查代码发现buf与P的大小并不一致。[mw_shl_code=c,true]buf[4*i+0]=p[0];
buf[4*i+1]=p[1];
buf[4*i+2]=p[0];
buf[4*i+3]=p[1];
p+=2;[/mw_shl_code]

buf的大小是P的两倍。因些在分配内存时应按需分配。因此对wav_play_song(u8* fname) 进行修改。将原代码:

[mw_shl_code=c,true]audiodev.i2sbuf1=mymalloc(SRAMIN,WAV_I2S_TX_DMA_BUFSIZE);
audiodev.i2sbuf2=mymalloc(SRAMIN,WAV_I2S_TX_DMA_BUFSIZE);
audiodev.tbuf=mymalloc(SRAMIN,WAV_I2S_TX_DMA_BUFSIZE);[/mw_shl_code]

改为:
[mw_shl_code=c,true]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);[/mw_shl_code]

测试声音播放正常。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-19 22:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表