- 论坛徽章:
- 5
|
- 此外,所有的混音通道都有单声道和双声道的区别,如果需要知道哪些混音通道提供了对立体声的支持,可以通过SOUND_MIXER_READ_STEREODEVS来获得。
- 4.3 音频录放框架
- 下面给出一个利用声卡上的DSP设备进行声音录制和回放的基本框架,它的功能是先录制几秒种音频数据,将其存放在内存缓冲区中,然后再进行回放,其所有的功能都是通过读写/dev/dsp设备文件来完成的:
- /*
- * sound.c
- */
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/ioctl.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <linux/soundcard.h>
- #define LENGTH 3 /* 存储秒数 */
- #define RATE 8000 /* 采样频率 */
- #define SIZE 8 /* 量化位数 */
- #define CHANNELS 1 /* 声道数目 */
- /* 用于保存数字音频数据的内存缓冲区 */
- unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
- int main()
- {
- int fd; /* 声音设备的文件描述符 */
- int arg; /* 用于ioctl调用的参数 */
- int status; /* 系统调用的返回值 */
- /* 打开声音设备 */
- fd = open("/dev/dsp", O_RDWR);
- if (fd < 0) {
- perror("open of /dev/dsp failed");
- exit(1);
- }
- /* 设置采样时的量化位数 */
- arg = SIZE;
- status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
- if (status == -1)
- perror("SOUND_PCM_WRITE_BITS ioctl failed");
- if (arg != SIZE)
- perror("unable to set sample size");
- /* 设置采样时的声道数目 */
- arg = CHANNELS;
- status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
- if (status == -1)
- perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
- if (arg != CHANNELS)
- perror("unable to set number of channels");
- /* 设置采样时的采样频率 */
- arg = RATE;
- status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
- if (status == -1)
- perror("SOUND_PCM_WRITE_WRITE ioctl failed");
- /* 循环,直到按下Control-C */
- while (1) {
- printf("Say something:\n");
- status = read(fd, buf, sizeof(buf)); /* 录音 */
- if (status != sizeof(buf))
- perror("read wrong number of bytes");
- printf("You said:\n");
- status = write(fd, buf, sizeof(buf)); /* 回放 */
- if (status != sizeof(buf))
- perror("wrote wrong number of bytes");
- /* 在继续录音前等待回放结束 */
- status = ioctl(fd, SOUND_PCM_SYNC, 0);
- if (status == -1)
- perror("SOUND_PCM_SYNC ioctl failed");
- }
- }
-
- 4.4 混音器框架
- 下面再给出一个对混音器进行编程的基本框架,利用它可以对各种混音通道的增益进行调节,其所有的功能都是通过读写/dev/mixer设备文件来完成的:
- /*
- * mixer.c
- */
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <linux/soundcard.h>
- /* 用来存储所有可用混音设备的名称 */
- const char *sound_device_names[] = SOUND_DEVICE_NAMES;
- int fd; /* 混音设备所对应的文件描述符 */
- int devmask, stereodevs; /* 混音器信息对应的位图掩码 */
- char *name;
- /* 显示命令的使用方法及所有可用的混音设备 */
- void usage()
- {
- int i;
- fprintf(stderr, "usage: %s <device> <left-gain%%> <right-gain%%>\n"
- " %s <device> <gain%%>\n\n"
- "Where <device> is one of:\n", name, name);
- for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)
- if ((1 << i) & devmask) /* 只显示有效的混音设备 */
- fprintf(stderr, "%s ", sound_device_names[i]);
- fprintf(stderr, "\n");
- exit(1);
- }
- int main(int argc, char *argv[])
- {
- int left, right, level; /* 增益设置 */
- int status; /* 系统调用的返回值 */
- int device; /* 选用的混音设备 */
- char *dev; /* 混音设备的名称 */
- int i;
- name = argv[0];
- /* 以只读方式打开混音设备 */
- fd = open("/dev/mixer", O_RDONLY);
- if (fd == -1) {
- perror("unable to open /dev/mixer");
- exit(1);
- }
-
- /* 获得所需要的信息 */
- status = ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
- if (status == -1)
- perror("SOUND_MIXER_READ_DEVMASK ioctl failed");
- status = ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs);
- if (status == -1)
- perror("SOUND_MIXER_READ_STEREODEVS ioctl failed");
- /* 检查用户输入 */
- if (argc != 3 && argc != 4)
- usage();
- /* 保存用户输入的混音器名称 */
- dev = argv[1];
- /* 确定即将用到的混音设备 */
- for (i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++)
- if (((1 << i) & devmask) && !strcmp(dev, sound_device_names[i]))
- break;
- if (i == SOUND_MIXER_NRDEVICES) { /* 没有找到匹配项 */
- fprintf(stderr, "%s is not a valid mixer device\n", dev);
- usage();
- }
- /* 查找到有效的混音设备 */
- device = i;
- /* 获取增益值 */
- if (argc == 4) {
- /* 左、右声道均给定 */
- left = atoi(argv[2]);
- right = atoi(argv[3]);
- } else {
- /* 左、右声道设为相等 */
- left = atoi(argv[2]);
- right = atoi(argv[2]);
- }
-
- /* 对非立体声设备给出警告信息 */
- if ((left != right) && !((1 << i) & stereodevs)) {
- fprintf(stderr, "warning: %s is not a stereo device\n", dev);
- }
-
- /* 将两个声道的值合到同一变量中 */
- level = (right << 8) + left;
-
- /* 设置增益 */
- status = ioctl(fd, MIXER_WRITE(device), &level);
- if (status == -1) {
- perror("MIXER_WRITE ioctl failed");
- exit(1);
- }
- /* 获得从驱动返回的左右声道的增益 */
- left = level & 0xff;
- right = (level & 0xff00) >> 8;
- /* 显示实际设置的增益 */
- fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right);
- /* 关闭混音设备 */
- close(fd);
- return 0;
- }
-
- 编译好上面的程序之后,先不带任何参数执行一遍,此时会列出声卡上所有可用的混音通道:
- [xiaowp@linuxgam sound]$ ./mixer
- usage: ./mixer <device> <left-gain%> <right-gain%>
- ./mixer <device> <gain%>
-
- Where <device> is one of:
- vol pcm speaker line mic cd igain line1 phin video
-
- 之后就可以很方便地设置各个混音通道的增益大小了,例如下面的命令就能够将CD输入的左、右声道的增益分别设置为80%和90%:
- [xiaowp@linuxgam sound]$ ./mixer cd 80 90
- cd gain set to 80% / 90%
-
-
- 回页首
-
- 五、小结
- 随着Linux平台下多媒体应用的逐渐深入,需要用到数字音频的场合必将越来越广泛。虽然数字音频牵涉到的概念非常多,但在Linux下进行最基本的音频编程却并不十分复杂,关键是掌握如何与OSS或者ALSA这类声卡驱动程序进行交互,以及如何充分利用它们提供的各种功能,熟悉一些最基本的音频编程框架和模式对初学者来讲大有裨益。
- 参考资料
- 1. OSS是Linux上最早出现的声卡驱动程序,[url]http://www.opensound.com[/url]是它的核心网站,从中可以了解到许多与OSS相关的信息。
- 2. ALSA是目前广泛使用的Linux声卡驱动程序,并且提供了一些库函数来简化音频程序的编写,在其官方网站[url]http://www.alsa-project.org/[/url]上可以了解到ALSA的许多信息,并能够下载到最新的驱动程序和工具软件。
- 3. Ken C. Pohlmann著,苏菲译,数字音频原理与应用(第四合版),北京:电子工业出版社,2002
- 4. 钟玉琢等编著,多媒体技术及其应用,北京:机械工业出版社,2003
- 关于作者
-
- 本文作者肖文鹏是一名自由软件爱好者,主要从事操作系统和分布式计算环境的研究,喜爱Linux和Python。你可以通过 [email]xiaowp@263.net[/email]与他取得联系。
-
复制代码 |
|