经过一年的技术积累,发现这个问题解决起来特别简单,只需要给amixer加上-M参数即可实现amixer与alsamixer音量同步了。
sudo amixer -M set PCM 50%
这样就可以了。。。还是官方文档最重要呀!
amixer文档对于该参数的解释如下
-M Use the mapped volume for evaluating the percentage representation like alsamixer, to be more natural for human ear.
====以下为当年原文=====2017年10月30日 10:51:56
最近在开发基于树莓派的一个智能硬件设备,其中用到了Alsa的音频播放功能。因为有一个需求是需要在WEB页面的管理端调节音量,所以就不能使用GUI了。
玩过树莓派音频播放的同学应该都知道树莓派在alsa有两种调节音量的方式。
第一种 是通过alsamixer这个命令来调,在终端执行这个命令后,会出现一个通过方向键调音量的界面,使用上下方向键就可以调节音量了。
第二种 就是通过
sudo amixer set PCM 50%
这样的命令来修改音量。
接下来就是问题所在了。当我在用命令来调节音量的时候,发现通过amixer命令调节的音量百分比总是和alsamixer 界面中的百分比不相符,而且他们之间还不是一个线性的规律。
举例,当我在命令中输入的音量是10%是,界面显示的是2%,命令输入40%,界面显示的是9%……等等。然后为了寻找原因,我特意采集了20个数据点,用Excel生成了一个散点图,来观察他们之间的关系(不得不说Excel处理数据的功能是真6!)。
生成的图后,利用Excel对数据的处理功能生成了一个函数,我才惊讶的发现,原来我输入的音量百分比和实际的音量百分比竟然是一个对数型的函数!如下图。
通过图可以得知,他的函数为
y = 24.979ln(x) - 14.581
既然找到了关系函数,那我们就可以通过函数来计算出我们想要的音量啦~比如我想要获取20,将20带入到这个函数的x中,
y = 24.979ln(20)-14.581就可以计算出应该输入的音量是60.24。
现在根据真正的音量我们可以计算出应该输入的音量了,但是我们想获取音量怎么办?树莓派通过amixer获取的音量其实也遵从这个函数,只不过是xy对调了,变成了这个函数的反函数,在这里直接贴出他的反函数
y = 1.7972e^(0.04x)
通过这个函数,我们就可以利用
amixer cget
命令来获取音量,计算出真正的音量啦!这个功能本人是用PHP来写的,贴上部分代码以供参考!
//修改音量
public function ajax_modify_volume(){
$volume = $this->input->post('volume');
//树莓派通过命令更改的音量和实际并不相符,而是一个对数型的函数。
//比如,我输入amixer set PCM 45%,通过alsaplayer发现实际音量是11
//60%对应的实际音量是20,等等。
//所以要通过一个根据很多数据得到的函数进行计算才能获取正确的音量。
//y = 24.979ln(x) - 14.581 x为想要获取的音量,y为实际应该填入的音量
//y = 1.7972e^(0.04x) x为填入的音量,y为实际音量
if((int)$volume > 75){
$volume = 75;
}
$volume = 24.979 * log((int)$volume) - 14.581;
echo $volume;
`sudo amixer set PCM $volume%`;
`alsactl store`;
//返回200状态码
header("HTTP/1.1 200 OK");
}
//获取音量
public function ajax_get_volume(){
//树莓派的音量范围是-10239~400,以下获取的只是一个值,需要通过公式计算才能正确得到百分比。
$volume = `sudo amixer cget numid=1 | grep ': values'|awk -F = '{print $2}'`;
//以下计算目的是计算出一个值在上述范围中所占的比例,比如400 在这个范围就是100%,-10239在这个范围就时0%
$v = (float)$volume;
$v = 400 - $v;
$v = $v / 10639;
$v = 1 - $v;
//获得百分比。
$v = $v * 100;
//通过y = 1.7972e^(0.04x) x为填入的音量,y为实际音量 这个公式计算出实际音量。
$v = 1.7972 * pow(2.718,0.04 * $v);
//四舍五入,获得整数
echo round($v);
}