专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »嵌入式开发 » linux编程:Linux 声音设备编程 »正文

linux编程:Linux 声音设备编程

来源: 发布时间:星期四, 2008年12月11日 浏览:8次 评论:0

KdRfbaiducuk72f    其实 Linux 下声音设备编程比大多数人想象要简单得多般说来我们常用声音设备是内部扬声器和声卡它们都对应 /dev 目录下个或多个设备文件我们象打开普通文件样打开它们用 ioctl()设置些参数然后对这些打开特殊文件进写操作
KdRfbaiducuk72f  由于这些文件不是普通文件所以我们不能用 ANSI C(标准C) fopen、fclose 等来操作文件而应该使用系统文件 I/O 处理(open、read、write、lseek 和 close)来处理这些设备文件ioctl()或许是 Linux 下最庞杂它可以控制各种文件属性在 Linux 声音设备编程中最重要就是使用此正确设置必要参数
KdRfbaiducuk72f  下面我们举两个实际例子来说明如何实现 Linux 下声音编程由于此类编程涉及到系统设备读写所以很多时候需要你有 root 权限如果你将下面例子编译后不能正确执行那么首先请你检查是否是没有操纵某个设备权限
KdRfbaiducuk72f
KdRfbaiducuk72f1. 对内部扬声器编程
KdRfbaiducuk72f  内部扬声器是控制台部分所以它对应设备文件为 /dev/console变量 KIOCSOUND 在头文件 /usr / /linux /kd.h 中声明ioctl 使用它可以来控制扬声器发声使用规则为:
KdRfbaiducuk72f  ioctl ( fd, KIOCSOUND, () tone);
KdRfbaiducuk72f  fd 为文件设备号tone 是音频值当 tone 为 0 时终止发声必须是它所理解音频和我们平常以为音频是不同由于计算机主板定时器时钟频率为 1.19MHZ所以要进行正确发声必须进行如下转换:
KdRfbaiducuk72f  扬声器音频值 = 1190000/ 我们期望音频值
KdRfbaiducuk72f  扬声器发声时间长短我们通过 usleep(unsigned long usec)来控制它是在头文件 /usr / /unistd.h 中定义睡眠 usec 微秒下面即是让扬声器按指定长度和音频发声完整清单:
KdRfbaiducuk72f
KdRfbaiducuk72f# < fcntl.h >
KdRfbaiducuk72f# < stdio.h >
KdRfbaiducuk72f# < stdlib.h >
KdRfbaiducuk72f# < .h >
KdRfbaiducuk72f# < unistd.h >
KdRfbaiducuk72f# < sys/ioctl.h >
KdRfbaiducuk72f# < sys/types.h >
KdRfbaiducuk72f# < linux/kd.h >
KdRfbaiducuk72f
KdRfbaiducuk72f/* 设定默认值 */
KdRfbaiducuk72f# DEFAULT_FREQ 440 /* 设定个合适频率 */
KdRfbaiducuk72f# DEFAULT_LENGTH 200 /* 200 微秒发声长度是以微秒为单位*/
KdRfbaiducuk72f# DEFAULT_REPS 1 /* 默认不重复发声 */
KdRfbaiducuk72f# DEFAULT_DELAY 100 /* 同样以微秒为单位*/
KdRfbaiducuk72f
KdRfbaiducuk72f/* 定义个结构存储所需数据*/
KdRfbaiducuk72ftypedef struct {
KdRfbaiducuk72f freq; /* 我们期望输出频率单位为Hz */
KdRfbaiducuk72f length; /* 发声长度以微秒为单位*/
KdRfbaiducuk72f reps; /* 重复次数*/
KdRfbaiducuk72f delay; /* 两次发声间隔以微秒为单位*/
KdRfbaiducuk72f} beep_parms_t;
KdRfbaiducuk72f
KdRfbaiducuk72f
KdRfbaiducuk72f/* 打印帮助信息并退出*/
KdRfbaiducuk72fvoid usage_bail ( const char *executable_name ) {
KdRfbaiducuk72fprf ( "Usage: \n \t%s [-f frequency] [-l length] [-r reps] [-d delay] \n ",
KdRfbaiducuk72fexecutable_name );
KdRfbaiducuk72fexit(1);
KdRfbaiducuk72f}
KdRfbaiducuk72f
KdRfbaiducuk72f/ * 分析运行参数各项意义如下:
KdRfbaiducuk72f* "-f <以 HZ 为单位频率值 >"
KdRfbaiducuk72f* "-l <以毫秒为单位发声时长 >"
KdRfbaiducuk72f* "-r <重复次数 >"
KdRfbaiducuk72f* "-d <以毫秒为单位间歇时长 >"
KdRfbaiducuk72f*/
KdRfbaiducuk72fvoid parse_command_line(char **argv, beep_parms_t *result) {
KdRfbaiducuk72fchar *arg0 = *(argv);
KdRfbaiducuk72fwhile ( *argv ) {
KdRfbaiducuk72f ( !strcmp( *argv,"-f" )) { /*频率*/
KdRfbaiducuk72f freq = atoi ( *( argv ) );
KdRfbaiducuk72f ( ( freq <= 0 ) | | ( freq > 10000 ) ) {
KdRfbaiducuk72ffprf ( stderr, "Bad parameter: frequency must be from 1..10000\n" );
KdRfbaiducuk72fexit (1) ;
KdRfbaiducuk72f} {
KdRfbaiducuk72fresult->freq = freq;
KdRfbaiducuk72fargv;
KdRfbaiducuk72f}
KdRfbaiducuk72f} ( ! strcmp ( *argv, "-l" ) ) { /*时长*/
KdRfbaiducuk72f length = atoi ( *(argv ) );
KdRfbaiducuk72f (length < 0) {
KdRfbaiducuk72ffprf(stderr, "Bad parameter: length must be >= 0\n");
KdRfbaiducuk72fexit(1);
KdRfbaiducuk72f} {
KdRfbaiducuk72fresult->length = length;
KdRfbaiducuk72fargv;
KdRfbaiducuk72f}
KdRfbaiducuk72f} (!strcmp(*argv, "-r")) { /*重复次数*/
KdRfbaiducuk72f reps = atoi(*(argv));
KdRfbaiducuk72f (reps < 0) {
KdRfbaiducuk72ffprf(stderr, "Bad parameter: reps must be >= 0\n");
KdRfbaiducuk72fexit(1);
KdRfbaiducuk72f} {
KdRfbaiducuk72fresult->reps = reps;
KdRfbaiducuk72fargv;
KdRfbaiducuk72f}
KdRfbaiducuk72f} (!strcmp(*argv, "-d")) { /* 延时 */
KdRfbaiducuk72f delay = atoi(*(argv));
KdRfbaiducuk72f (delay < 0) {
KdRfbaiducuk72ffprf(stderr, "Bad parameter: delay must be >= 0\n");
KdRfbaiducuk72fexit(1);
KdRfbaiducuk72f} {
KdRfbaiducuk72fresult->delay = delay;
KdRfbaiducuk72fargv;
KdRfbaiducuk72f}
KdRfbaiducuk72f} {
KdRfbaiducuk72ffprf(stderr, "Bad parameter: %s\n", *argv);
KdRfbaiducuk72fusage_bail(arg0);
KdRfbaiducuk72f}
KdRfbaiducuk72f}
KdRfbaiducuk72f}
KdRfbaiducuk72f
KdRfbaiducuk72f ( argc, char **argv) {
KdRfbaiducuk72f console_fd;
KdRfbaiducuk72f i; /* 循环计数器 */
KdRfbaiducuk72f/* 设发声参数为默认值*/
KdRfbaiducuk72fbeep_parms_t parms = {DEFAULT_FREQ, DEFAULT_LENGTH, DEFAULT_REPS,
KdRfbaiducuk72fDEFAULT_DELAY};
KdRfbaiducuk72f/* 分析参数可能话更新发声参数*/
KdRfbaiducuk72fparse_command_line(argv, &parms);
KdRfbaiducuk72f
KdRfbaiducuk72f/* 打开控制台失败则结束*/
KdRfbaiducuk72f ( ( console_fd = open ( "/dev/console", O_WRONLY ) ) -1 ) {
KdRfbaiducuk72ffprf(stderr, "Failed to open console.\n");
KdRfbaiducuk72fperror("open");
KdRfbaiducuk72fexit(1);
KdRfbaiducuk72f}
KdRfbaiducuk72f
KdRfbaiducuk72f/* 真正开始让扬声器发声*/
KdRfbaiducuk72ffor (i = 0; i < parms.reps; i) {
KdRfbaiducuk72f/* 数字 1190000 从何而来不得而知*/
KdRfbaiducuk72f magical_fairy_number = 1190000/parms.freq;
KdRfbaiducuk72f
KdRfbaiducuk72fioctl(console_fd, KIOCSOUND, magical_fairy_number); /* 开始发声 */
KdRfbaiducuk72fusleep(1000*parms.length); /*等待... */
KdRfbaiducuk72fioctl(console_fd, KIOCSOUND, 0); /* 停止发声*/
KdRfbaiducuk72fusleep(1000*parms.delay); /* 等待... */
KdRfbaiducuk72f} /* 重复播放*/
KdRfbaiducuk72f EXIT_SUCCESS;
KdRfbaiducuk72f}
KdRfbaiducuk72f  将上面例子稍作扩展用户即可以让扬声器唱歌只要找到五线谱或简谱音阶、音长、节拍和频率、发声时长、间隔对应关系就可以了我现在还记得以前在 DOS 下编写出世上只有妈妈好兴奋最后些提外话这其实是个很简单但是我们却用了很长篇幅希望读者从以上代码里能体会到写好些方法或许最重要是添加注释吧注释永远不会嫌多即便你写时候觉得它根本是多余但相信我相信曾这样告诉我们许多优秀员:养成写很多注释习惯
KdRfbaiducuk72f
KdRfbaiducuk72f2. 对声卡编程
KdRfbaiducuk72f  只要我们不是进行诸如驱动设备开发之类工作对声卡编程和上面对扬声器编程没有什么本质区别当你试图来编写诸如 CD 播放器、MP3 播放器之类复杂工作是取获得与CDROM 控制、MP3 解码之类信息而读写系统设备步在 Linux 下超互想象简单例如Linux下最简单播放 wav 只有行:cp $< >/dev/audio将它写成个 shell 文件同样是(shell 编程)
KdRfbaiducuk72f  我们首先需要知道台机器上是否有声卡个检查办法是检查文件 /dev/sndstat 文件如果打开此文件并且号是ENODEV则说明此机器没有安装声卡除此之外试着去打开文件 /dev/dsp 也可以来检查是否安装了声卡
KdRfbaiducuk72f  Linux 下和声卡相关文件有许多如采集数字样本 /dev/dsp文件针对混音器 /dev/mixer 文件以及用于音序器 /dev/sequencer 等文件 /dev/audio 是个基于兼容性考虑声音设备文件它实际是到上述数字设备个映射它最大特色或许是对诸如 wav 这类文件格式直接支持我们下面例子即使用了此设备文件实现了个简单录音机:我们从声卡设备(当然要用麦克风)读取音频数据并将它存放到文件 test.wav 中去要播放这个 wav 文件只要如前面所述使用命令 cp test.wav >/dev/audio 即可当然你也可以用 Linux 下其他多媒体软件来播放这个文件
KdRfbaiducuk72f下面即是完整清单:
KdRfbaiducuk72f
KdRfbaiducuk72f/* 此文件中定义了下面所有形如 SND_ 变量*/
KdRfbaiducuk72f#
KdRfbaiducuk72f#
KdRfbaiducuk72f#
KdRfbaiducuk72f#
KdRfbaiducuk72f#
KdRfbaiducuk72f
KdRfbaiducuk72f
KdRfbaiducuk72f{
KdRfbaiducuk72f/* id:读取音频文件描述符;fd:写入文件描述符ij为临时变量*/
KdRfbaiducuk72f id,fd,i,j;
KdRfbaiducuk72f/* 存储音频数据缓冲区可以调整*/
KdRfbaiducuk72fchar testbuf[4096];
KdRfbaiducuk72f/* 打开声卡设备失败则退出*/
KdRfbaiducuk72f ( ( id = open ( "/dev/audio", O_RDWR ) ) < 0 ) {
KdRfbaiducuk72ffprf (stderr, " Can’t open sound device!\n");
KdRfbaiducuk72fexit ( -1 ) ;
KdRfbaiducuk72f}
KdRfbaiducuk72f/* 打开输出文件失败则退出*/
KdRfbaiducuk72f ( ( fd = open ("test.wav",O_RDWR))<0){
KdRfbaiducuk72ffprf ( stderr, " Can’t open output file!\n");
KdRfbaiducuk72fexit (-1 );
KdRfbaiducuk72f}
KdRfbaiducuk72f/* 设置适当参数使得声音设备工作正常*/
KdRfbaiducuk72f/* 详细情况请参考Linux关于声卡编程文档*/
KdRfbaiducuk72fi=0;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_RESET,(char *)&i) ;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_SYNC,(char *)&i);
KdRfbaiducuk72fi=1;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_NONBLOCK,(char *)&i);
KdRfbaiducuk72fi=8000;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_SPEED,(char *)&i);
KdRfbaiducuk72fi=1;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_CHANNELS,(char *)&i);
KdRfbaiducuk72fi=8;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_SETFMT,(char *)&i);
KdRfbaiducuk72fi=3;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_SETTRIGGER,(char *)&i);
KdRfbaiducuk72fi=3;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_SETFRAGMENT,(char *)&i);
KdRfbaiducuk72fi=1;
KdRfbaiducuk72fioctl (id,SNDCTL_DSP_PROFILE,(char *)&i);
KdRfbaiducuk72f/* 读取定数量音频数据并将之写到输出文件中去*/
KdRfbaiducuk72ffor ( j=0; j<10;){
KdRfbaiducuk72fi=read(id,testbuf,4096);
KdRfbaiducuk72f(i>0){
KdRfbaiducuk72fwrite(fd,filebuf,i);
KdRfbaiducuk72fj;
KdRfbaiducuk72f}
KdRfbaiducuk72f}
KdRfbaiducuk72f/* 关闭输入、输出文件*/
KdRfbaiducuk72fclose(fd);
KdRfbaiducuk72fclose(id);
KdRfbaiducuk72f}
KdRfbaiducuk72f

相关文章

读者评论

  • 共0条 分0页

发表评论

  • 昵称:
  • 内容: