免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6259 | 回复: 5
打印 上一主题 下一主题

对linux下音频编程感兴趣的可进来看看 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-10-19 16:57 |只看该作者 |倒序浏览
在坛里也放了几篇关于linux下音频编程方面的帖子,我知道对这方面感兴趣的人不多。但一个月的心血终有小成,欣慰之余,也愿意将自己的收获与大家分享。
关于音频编程其实不外乎这么几个方面:播放音频文件,从mic或line录制wave stream,内录,播放音量的调节,播放进度的控制等。下面就从这几个方面和大家探讨。
也许很多人试过这样的命令:cat xxx.au >;/dev/dsp,回车后就能听到声音,但声音的质量却太让人不敢恭维,为什么?因为没有设置播放参数,驱动程序是按照缺省设置来放音的,下面给出一段演示程序:
……………………
    #define PCM_WAVE_FORMAT  1
    #define DEFAULT_START 0
    #define RECORD_RATE 48000
    #define RECORD_SIZE 16      
    #define RECORD_CHANNELS 2
……………………
    dfd =  open("/dev/dsp", O_RDWR);
    if(dfd == -1)
    {  
        perror("Unable to open /dev/dsp(are you root?)\n";
        return FALSE;
    }
    status = ioctl(dfd, SNDCTL_DSP_SETFMT, &arg);
    if (status == -1)
    {  
        perror("SOUND_PCM_WRITE_BITS ioctl failed";
        return FALSE;
    }
    if (arg != RECORD_SIZE)
    {   
        perror("unable to set sample size";
        return FALSE;
    }
    status=ioctl(dfd,SNDCTL_DSP_SETFMT,&format);
    if(status == -1)
    {
        perror("SNDCTL_DSP_SETFMT fail";
        return FALSE;
    }
    if(format!=AFMT_S16_LE)
    {
        perror("unable to set format of sample";
        return FALSE;
    }
    arg = RECORD_CHANNELS;
    status = ioctl(dfd, SNDCTL_DSP_CHANNELS, &arg);
    if (status == -1)
    {
        perror("SOUND_PCM_WRITE_CHANNELS ioctl failed";       
        return FALSE;
    }
    if (arg != RECORD_CHANNELS)
    {  
        perror("unable to set number of channels";
        return FALSE;
    }
    arg = RECORD_RATE;
    status = ioctl(dfd, SOUND_PCM_WRITE_RATE, &arg);
    if (status == -1)
    {
        perror("SOUND_PCM_WRITE_WRITE ioctl failed";
        return FALSE;
    }
    if(arg!=RECORD_RATE)
    {   
        perror("unable to set Rate";
        return FALSE;
    }
    return TRUE;  
上面的各项参数代表什么意思,为什么这么设在网上有很多这样的文章,大家可以去查。初始化完音频设备后,这时我们再write音频数据到/dev/dsp,效果将会有明显的好转。

在linux下录制声音,主要就是录音设备的选择,输入输出增益的调节,同时还要控制好不要被非当前用来录音的录音设备干扰。
进行到这一步,我们必须对linux下声卡驱动有所了解。当前最有名的当数OSS(open sound system)和ALSA(Advanced Linux Sound Architecture),相对而言,oss是商业
组织开发和维护的,对硬件的支持较好,较成熟,但对于商业用途的要收费。ALSA是自由者维护的自由项目,具有更加友好的编程接口,且完全兼容于OSS,对应用程序员来讲无疑是一个更佳的选择。
这里主要是基于OSS的开发。oss对混音通道(包括mic,line,cd等等)的管理,详情见http://www.opensound.com/pguide/oss.pdf。
要选择录音源,首先需获得当前设备状态,有那些能作为录音源。看下面的代码:
    int currentRecmask = 0, newrecmask = 0;   

    if((ioctl(dfd, SOUND_MIXER_READ_RECMASK, ¤tRecmask)) == -1)
    {
        return FALSE;
    }
        if(!((1 << device) & currentRecmask))
    {
        return FALSE;
    }
输出currentRecmask:7356865(并不一定就是它了,它只是我当前系统的值)
转化为二进制为:11100000100000111000001。
这个值是什么意思呢?原来,oss 为每一个混音通道都定义了一个Macro,详见/usr/include/linux/soundcard.h,从0到25
上面这个二进制数从右往左就是通道宏从0到25能否用来录音的状态,1表示能,0则不能。device则表示0-25的序号,观察一下
soundcard.h,相信你能马上从混音通道的名字得到这个序号。

    newrecmask |= (1 << device);
   
    /*change record source*/
    if (ioctl(dfd, SOUND_MIXER_WRITE_RECSRC, &newrecmask) == -1)
    {
        return FALSE;
    }
上面这段代码则是设置device为录音源,ex,mic的device为7,但在soundcard.h却排在8,所以将1左移7为就搞好在那个位置了。
在录音时要注意应用程序的Buffer不应大于内核的Buffer,同时,应是采样频率的正整数倍,以前我因为没注意到这点,基本上
录不到声音。好了,设置录音源讲到这,再来看看怎么设置音量。看如下的代码:
    int value = 0;
    value = left | (right << ;
  
    if((ioctl(dfd, MIXER_WRITE(device), &value)) == -1)
    {
        perror("Set volumn fail!";
        return FALSE;
    }  
    return TRUE;   
对于只有一个混音通道的单声道设备来说,返回的增益大小保存在低位字节中。而对于支持多个混音通道的双声道设备来说,返回的增益大小实际上包括两个部分,分别代表左、右两个声道的值,
其中低位字节保存左声道的音量,而高位字节则保存右声道的音量。device值同上。

评分

参与人数 1可用积分 +15 收起 理由
T-bagwell + 15 原创内容

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2008-12-08 18:23 |只看该作者
发表这么久了,都没人顶....
哎,我来晚了!
顶起

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
3 [报告]
发表于 2008-12-08 20:06 |只看该作者

回复 #1 grep_one 的帖子

代码用 [code][/code] 括起来。

论坛徽章:
0
4 [报告]
发表于 2009-04-14 16:26 |只看该作者
这才是有用的东西,原创的
我在网上找了好久这方面的东西,净是一些没什么大用的文章,还让SB们转来转去,真TM无聊


不过你贴的代码不是完整的呀!
    if((ioctl(dfd, SOUND_MIXER_READ_RECMASK, ¤tRecmask)) == -1)
    {
        return FALSE;
    }
  
tRecmask应该是打错了吧?应该是currentRecmask?

    if(!((1 << device) & currentRecmask))
    {
        return FALSE;
    }
上面这几句,难道不是在for循环里进行吗????

[ 本帖最后由 也是菜鸟 于 2009-4-14 16:33 编辑 ]

论坛徽章:
5
摩羯座
日期:2014-07-22 09:03:552015元宵节徽章
日期:2015-03-06 15:50:392015亚冠之大阪钢巴
日期:2015-06-12 16:01:352015年中国系统架构师大会
日期:2015-06-29 16:11:2815-16赛季CBA联赛之四川
日期:2018-12-17 14:10:21
5 [报告]
发表于 2009-04-14 16:33 |只看该作者
之前做过相关的工作,楼主总结的还可以,给点分,呵呵
尤其是左声道右声道部分,我以前遇到过类似问题,后来发现是我去掉了一个声道,导致插声音线的时候有一边有声有一边没声

论坛徽章:
0
6 [报告]
发表于 2013-02-20 23:20 |只看该作者
MARK一个,以后估计用得到
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP