基于uda1340 的 mixer混音器编程实例

xiaoxiao2021-02-28  112

今日诗词推荐:

                                  岳飞   《满江红》  

    怒发冲冠,凭阑处、潇潇雨歇。抬望眼、仰天长啸,壮怀激烈。三十功名尘与土,八千里路云和月。莫等闲,白了少年头,空悲切。 

  靖康耻,犹未雪;臣子恨,何时灭。驾长车,踏破贺兰山缺。壮志饥餐胡虏肉,笑谈渴饮匈奴血。待从头、收拾旧山河,朝天阙。

==========================================================================

主机操作系统:Centos 6.7  交叉编译器环境:arm-linux-gcc-4.5.4 (可通过命令/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux-gcc -v查询) 开发板平台: fl2440  Linux内核版本: linux-3.0 .54

声卡:uda1341(音频编程接口:ALSA)

==========================================================================

一、什么是mixer:

在声卡的硬件电路中,混音器(mixer)是一个很重要的组成部分,它的作用是将多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不相同。运行在Linux内核中的声卡驱动程序一般都会提供/dev/mixer这一设备文件,它是应用程序对混音器进行操作的软件接口。混音器电路通常由两个部分组成:输入混音器(input mixer)和输出混音器(output mixer)。  输入混音器负责从多个不同的信号源接收模拟信号,这些信号源有时也被称为混音通道或者混音设备。模拟信号通过增益控制器和由软件控制的音量调节器后,在不同的混音通道中进行级别(level)调制,然后被送到输入混音器中进行声音的合成。混音器上的电子开关可以控制哪些通道中有信号与混音器相连,有些声卡只允许连接一个混音通道作为录音的音源,而有些声卡则允许对混音通道做任意的连接。经过输入混音器处理后的信号仍然为模拟信号,它们将被送到A/D转换器进行数字化处理。  输出混音器的工作原理与输入混音器类似,同样也有多个信号源与混音器相连,并且事先都经过了增益调节。当输出混音器对所有的模拟信号进行了混合之后,通常还会有一个总控增益调节器来控制输出声音的大小,此外还有一些音调控制器来调节输出声音的音调。经过输出混音器处理后的信号也是模拟信号,它们最终会被送给喇叭或者其它的模拟输出设备。对混音器的编程包括如何设置增益控制器的级别,以及怎样在不同的音源间进行切换,这些操作通常来讲是不连续的,而且不会像录音或者放音那样需要占用大量的计算机资源。由于混音器的操作不符合典型的读/写操作模式,因此除了open和close两个系统调用之外,大部分的操作都是通过ioctl系统调用来完成的。与/dev/dsp不同,/dev/mixer允许多个应用程序同时访问,并且混音器的设置值会一直保持到对应的设备文件被关闭为止。  为了简化应用程序的设计,Linux上的声卡驱动程序大多都支持将混音器的ioctl操作直接应用到声音设备上,也就是说如果已经打开了/dev/dsp,那么就不用再打开/dev/mixer来对混音器进行操作,而是可以直接用打开/dev/dsp时得到的文件标识符来设置混音器。

二、mixer编程:

声卡上的混音器由多个混音通道组成,它们可以通过驱动程序提供的设备文件/dev/mixer进行编程。对混音器的操作是通过ioctl系统调用来完成的,并且所有控制命令都由SOUND_MIXER或者MIXER开头,表1列出了常用的几个混音器控制命令:

名 称作 用SOUND_MIXER_VOLUME主音量调节SOUND_MIXER_BASS低音控制SOUND_MIXER_TREBLE高音控制SOUND_MIXER_SYNTHFM合成器SOUND_MIXER_PCM主D/A转换器SOUND_MIXER_SPEAKERPC喇叭SOUND_MIXER_LINE音频线输入SOUND_MIXER_MIC麦克风输入SOUND_MIXER_CDCD输入SOUND_MIXER_IMIX回放音量SOUND_MIXER_ALTPCM从D/A 转换器SOUND_MIXER_RECLEV录音音量SOUND_MIXER_IGAIN输入增益SOUND_MIXER_OGAIN输出增益SOUND_MIXER_LINE1声卡的第1输入SOUND_MIXER_LINE2声卡的第2输入SOUND_MIXER_LINE3声卡的第3输入

        对声卡的输入增益和输出增益进行调节是混音器的一个主要作用,目前大部分声卡采用的是8位或者16位的增益控制器,但作为程序员来讲并不需要关心这些,因为声卡驱动程序会负责将它们变换成百分比的形式,也就是说无论是输入增益还是输出增益,其取值范围都是从0到100。在进行混音器编程时,可以使用SOUND_MIXER_READ宏来读取混音通道的增益大小,例如在获取麦克风的输入增益时,可以使用如下的代码:

int vol; ioctl(fd, SOUND_MIXER_READ(SOUND_MIXER_MIC), &vol); printf("Mic gain is at %d %%\n", vol);

        对于只有一个混音通道的单声道设备来说,返回的增益大小保存在低位字节中。而对于支持多个混音通道的双声道设备来说,返回的增益大小实际上包括两个部分,分别代表左、右两个声道的值,其中低位字节保存左声道的音量,而高位字节则保存右声道的音量。下面的代码可以从返回值中依次提取左右声道的增益大小:

int left, right; left = vol & 0xff; //等价于 vol & 0x00ff ,取低八位 right = (vol & 0xff00) >> 8; printf("Left gain is %d %%, Right gain is %d %%\n", left, right)

类似地,如果想设置混音通道的增益大小,则可以通过SOUND_MIXER_WRITE宏来实现,此时遵循的原则与获取增益值时的原则基本相同,例如下面的语句可以用来设置麦克风的输入增益: 

vol = (right << 8) + left; //还原增益 ioctl(fd, SOUND_MIXER_WRITE(SOUND_MIXER_MIC), &vol);

在编写实用的音频程序时,混音器是在涉及到兼容性时需要重点考虑的一个对象,这是因为不同的声卡所提供的混音器资源是有所区别的。声卡驱动程序提供了多个ioctl系统调用来获得混音器的信息,它们通常返回一个整型的位掩码(bitmask),其中每一位分别代表一个特定的混音通道,如果相应的位为1,则说明与之对应的混音通道是可用的。例如通过SOUND_MIXER_READ_DEVMASK返回的位掩码,可以查询出能够被声卡支持的每一个混音通道,而通过SOUND_MIXER_READ_RECMAS返回的位掩码,则可以查询出能够被当作录音源的每一个通道。下面的代码可以用来检查CD输入是否是一个有效的混音通道:

ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask); if (devmask & SOUND_MIXER_CD) printf("The CD input is supported");

如果进一步还想知道其是否是一个有效的录音源,则可以使用如下语句:

ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask); if (devmask & SOUND_MIXER_CD) printf("The CD input is supported");

目前大多数声卡提供多个录音源,通过SOUND_MIXER_READ_RECSRC可以查询出当前正在使用的录音源,同一时刻能够使用几个录音源是由声卡硬件决定的。类似地,使用SOUND_MIXER_WRITE_RECSRC可以设置声卡当前使用的录音源,例如下面的代码可以将CD输入作为声卡的录音源使用:

ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask); if (devmask & SOUND_MIXER_CD) printf("The CD input is supported");

      此外,所有的混音通道都有单声道和双声道(两个耳机发声音)的区别,如果需要知道哪些混音通道提供了对立体声的支持,可以通过SOUND_MIXER_READ_STEREODEVS来获得。

三、编程实例:

该程序用于设置某混音设备的增益,通俗的说,比如vol设备代表音量,我们就可以用该程序设置。通过该程序对各设备设置增益,以使声音达到我们想要的效果。

#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; } 将程序用交叉编译器编译好后下载到开发板上,修改权限后运行。

 

先不带参数运行一下,它会执行usage()函数,该函数会打印提示信息,告诉我们这个函数用法。最主要的是它可以打印出可用设备名,我们可以看到一共有5个设备可用。那么我们可以来设置一下音量(vol).

>: ./mixer vol 80

这样,我们就把音量设置成了80,再用madplay播放歌曲,我们会发现音量与之前已经不同了。其他设备设置是一样的。不过双声道设备设置需要输入两个参数分别设置左、右声道。比如./mixer 设备名 80 90

        vol:       音量bass:    低音        treble:  在音响领域中就是调节中高频        mic:      麦克风        igain:    输入增益

本文参考博客:http://blog.csdn.net/kevinx_xu/article/details/8501231

转载请注明原文地址: https://www.6miu.com/read-85034.html

最新回复(0)