音频处理——解析PCM格式实例(音量调控)

举例

要注意的是,PCM的数据在内存中是纯数据的二进制,也就是说我们无法通过解析文件得知他的采样率、采样精度、声道数等信息,只能先得知它的参数再对其进行解析。

我用于解析的PCM文件参数如下

  • 采样精度——16bit
  • 采样率——16000Hz
  • 声道——单声道
  • 音频帧率——40
  • 每帧的采样点——640

波形如下
在这里插入图片描述
此文件为欢迎光临的语音

音频文件的尺寸 = 采样频率 x 采样精度 x 通道数 x 采样时间
于是示例文件的尺寸 = 16000 x 2 x 1 x 1.584 =   50688byte 

在这里插入图片描述

音量控制

我们先看一个真正的音频样本波形:
在这里插入图片描述
如果我们放大5倍波形,也就是振幅乘以5,此时我们听到了更大的声音,此时样本波形如下:
在这里插入图片描述
假如我们有2048bytesPCM数据,样本大小两个字节,共有1024个样本,我们要放大两倍声音,代码可以按如下写:

int16_t pcm[1024] = read in some pcm data;
for (ctr = 0; ctr < 1024; ctr++) 
{
	pcm[ctr] *= 2;
}

虽然看着是很简单,但是需要考虑一些问题

数据溢出

因为每个样本取值范围是有限制的,调节音量时不可能随便增大,比如一个signed 16 bits的样本,值为5000,我们放大10倍,由于有符号位16bits数据取值范围为-32768~32767,5000乘以10得到的50000超过了32767,数据溢出了,最后值可能变为-15536,不是我们期望的。此时我们就需要裁剪了,确保数值在正确范围内。如下代码对前面说到的放大两倍声音做了裁剪处理:

int16_t pcm[1024] = read in some pcm data;
int32_t pcmval;
for (ctr = 0; ctr < 1024; ctr++) 
{
    pcmval = pcm[ctr] * 2;
    if (pcmval < 32767 && pcmval > -32768) 
    {
        pcm[ctr] = pcmval
    } 
    else if (pcmval > 32767) 
    {
        pcm[ctr] = 32767;
    } 
    else if (pcmval < -32768) 
    {
        pcm[ctr] = -32768;
    }
}

对数描述

平时表示声音强度我们都是用分贝(db)作单位的,声学领域中,分贝的定义是声源功率与基准声功率比值的对数乘以10的数值。根据人耳的心理声学模型,人耳对声音感知程度是对数关系,而不是线性关系。人类的听觉反应是基于声音的相对变化而非绝对的变化。对数标度正好能模仿人类耳朵对声音的反应。所以用分贝作单位描述声音强度更符合人类对声音强度的感知。前面我们直接将声音乘以某个值,也就是线性调节,调节音量时会感觉到刚开始音量变化很快,后面调的话好像都没啥变化,使用对数关系调节音量的话声音听起来就会均匀增大。

如下图,横轴表示音量调节滑块,纵坐标表示人耳感知到的音量,图中取了两块横轴变化相同的区域,音量滑块滑动变化一样,
但是人耳感觉到的音量变化是不一样的,在左侧也就是较安静的地方,感觉到音量变化大,在右侧声音较大区域人耳感觉到的音量变化较小。

在这里插入图片描述
下面我们讲下音量值乘数取值,这里我只简单的用tan函数模拟,效果也不错,至于使用对数如何调整请参考文末链接:

 int some_level;
 float multiplier = tan (some_level / 100.0 );

上面代码中音量乘数取值为tan (some_level / 100.0 ),最后实现代码如下:

int16_t pcm[1024] = read in some pcm data;
int32_t pcmval;
uint8_t level = certain value;
float multiplier = tan(level/100.0);
for (ctr = 0; ctr < 1024; ctr++) {
    pcmval = pcm[ctr] * multiplier;
    if (pcmval < 32767 && pcmval > -32768) {
        pcm[ctr] = pcmval
    } else if (pcmval > 32767) {
        pcm[ctr] = 32767;
    } else if (pcmval < -32768) {
        pcm[ctr] = -32768;
    }
}

其中level取值需要具体测试实现,一般使用时level取值为某个范围的几个数,比如取10个数,这样音量就有10个阶跃可以调节。
如下图,最后声音音量近似按对数关系增长了:
在这里插入图片描述
如果想了解利用对数关系调节音量的具体实现,请参考:

PCM音量控制

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spark!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值