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

今日诗词推荐:

                                  岳飞   《满江红》  

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

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

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

主机操作系统: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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值