音频音量调整中的ramp up & down
在日常生活中不管是打电话还是听音乐,都会遇到音量不合适而去调整音量的情况。如果音量调整软件处理不好,就会听到pop noise。产生pop noise的原因是音量直接从当前值骤变到目标值,而不是缓慢的变。如果缓慢的变就不会有pop noise了。图1显示的是音量变大时骤变和缓慢变的示意图。图2显示的是音量变小时骤变和缓慢变的示意图。
在技术上音量缓升叫ramp up,音量缓降叫ramp down。本文就讲讲如何处理好ramp up & ramp down。
音量调整也叫增益(gain)调整。音量的单位是dB,计算公式是dB = 20*log(gain) 。gain = Y/X ,X是原始PCM值,Y是音量变后的PCM值。当音量不变时,即Y = X或者gain = 1,就是0 dB(20 *log(1) = 0 dB)。通常每增加6dB音量就翻倍,即Y = 2X或者gain = 2,(20 *log(2) = 6.02 dB)。通常音量变化范围是-88dB~12dB。软件实现时用的却是gain,因此要从dB换算成gain。由上面的计算dB的公式可以得到gain,gain = 10dB/20。为了减少运行时的运算量,就把音量(dB)和gain之间的mapping做成table。运行时只要根据dB值查表得到gain值。下表做了一个简单的示例。
float gain[101] = {
0.0000398, // -88 dB
0.0000447, // -87 dB
…..
1.0, // 0 dB
…..
2.0, // 6 dB
…..
};
原始PCM值乘以gain就是变化后的PCM值了,即 Y = X * gain。
音频处理算法通常都是定点实现的,这样就需要把gain table定点化,以Q4.27为例,得到下表的示例。
Int gain[101] = {
5343, // -88 dB
5995, // -87 dB
…..
134217728 , // 0 dB
…..
267799575, // 6 dB
…
};
在音量ramp过程中,要想做好ramp up & down,ramp过程中每个采样点的gain都是不一样的,从当前的gain值逐渐变到目标gain值。首先得定好指标:1ms变化多少dB(定义为dBPerMS), 这个确定了就可算出需要多少毫秒从当前音量变到目标音量。例如指标是1ms变化1dB,那么音量要从0dB变到12dB就需要12ms。采样率不同,1ms内的采样点数也不一样(定义为samplesPerMS)。以8K采样率为例,1ms内有8个采样点,即samplesPerMS = 8。知道了dBPerMS和samplesPerMS,就可算出每个采样点变化的dB,即 dBPerMS/samplesPerMS,记为ΔdB。上面算出的是ramp up时的值,当ramp down时,就是-ΔdB。
在ramp过程中假设当前采样点的音量为N dB,对应的gain记为g1,则下个采样点的音量为(N + Δ) dB,对应的gain记为g2。可以得到如下两个表达式:
N = 20 * log(g1) (1)
N + Δ = 20 * log(g2) (2)
(2)式 - (1)式得式(3)
Δ = 20 * log(g2) - 20 * log(g1) = 20 * log(g2/g1) (3)
所以
log(g2/g1) = Δ/20 , g2/g1 = 10Δ/20 , g2 = g1 * 10Δ/20 (4)
这样就得到了下个采样点的gain(g2)与当前采样点的gain(g1)的数学表达式(式4)。当g2的值到达目标gain时就不再更新。10Δ/20可以称为ramp factor,事先把这个值算好,在软件中做定值用。在不同的指标和采样率下有不同的值。例如dBPerMS = 0.5,samplesPerMS = 48,则Δ/20 = 0.0005208,rampUpFactor = 10Δ/20 = 1.0012,rampDownFactor = 10-Δ/20 = 0.9988。Ramp factor确定后就可去做gain更新了。以从0dB ramp up到6dB ramp factor是1.0012为例,0 dB时gain是1,6dB时目标gain是2。算每个采样点时当前采样点的gain都是前一个采样点gain的1.0012倍,一直到gain达到2后保持不变。
图3和图4是以正弦波为例做ramp up & down的原PCM和ramp后的PCM。
图3 原PCM波形和频谱
图4 ramp up & down后的波形和频谱
对上两图做一下解释。处理的是双声道的48k 采样的正弦波。通常声音刚开始播放时为了避免pop noise,会做一个ramp up,把音量从-88dB逐渐调整到0dB。30帧(每帧10ms)时,把音量调整到3dB,是个ramp up的过程。60帧时设成mute(mute是常见的一个场景,它可以算是音量调整中一个特例。mute时相当于把音量从当前值变为-88dB,unmute时就相当于把音量从-88dB变回去),是个ramp down的过程,几乎就听不到声音了。90帧时把音量设成0dB, 由于这时还处于mute,不生效,但音量值记住了。120帧时设成unmute,是个ramp up的过程,音量逐步变成0dB。150帧时把音量设成-6dB,是个ramp down的过程。
音频音量调整中的ramp up & down的更多相关文章
- 千位分隔符,音频音量加强,transform 垂直居中
1.最近做阴阳师日本官网,其中有个功能是获取预约人数,设计稿上的人数是这样151,567,000,想了想自己写还有点麻烦,于是网上copy了代码,再修改了下. 其中,有一点需要注意的是:函数中的str ...
- //点击按钮加减音频音量到最小会出现bug什么意思???
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- WebRTC与音频音量
WebRTC打开麦克风,获取音频,在网页上显示音量. 播放示例音频 先从播放音频入手.准备一个现成的音频文件. 界面上放一个audio元素,提前准备好一个音频文件,路径填入src <audio ...
- iOS音频采集过程中的音效实现
1.背景 在移动直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在采集录音的基础上玩一些花样. 比如演唱类的直播间中, 主播伴随着背景音乐演唱. ...
- 音频软件开发中的debug方法和工具
本文系作者原创.如转载,请注明出处. 谢谢! 音频软件开发同其他软件开发一样,都需要去调试.音频软件调试同其他软件调试方法有相同的地方,也有不同的地方,同时调试时还需要借助一些专门的工具,有了这些方法 ...
- C++ 调节PCM音频音量大小
在用解码器解码音频数据得到PCM音频数据块之后,可以在将数据送给声卡播放之前调节其音量大小,具体的实现函数如下: void RaiseVolume(char* buf, UINT32 size, UI ...
- 音频算法speex中的aec分析以及解析
算法原理: Speex的AEC是以NLMS(Normalized Least Mean Square)为基础,用MDF(multidelay block frequency domain)频域实现,最 ...
- alsa音频播放过程中的基本概念
以下为 ALSA-Project/FramesPeriods[1] 学习笔记 1, sample_rate: 即每秒进行多少次采样,常见的比如 8000.16000.44100和48000等 2, s ...
- Python-气象-大气科学-可视化绘图系列(三)—— 地图上自动标注省会名称(demo调整中)(代码+示例)
本文为原创文章 本文链接:https://www.cnblogs.com/zhanling/p/12606990.html # -*- coding: utf-8 -*- ''' Author: He ...
- moviepy音视频开发:audio_normalize调整剪辑音量大小到正常
☞ ░ 前往老猿Python博文目录 ░ 概述 audio_normalize函数用于将一个剪辑的音量大小调整到正常,调整的思路就是将剪辑中音频帧数据的最大值取出来,当其值小于1时,表示剪辑的音量偏小 ...
随机推荐
- JSP+servlet+mybatis+layui服装库存管理系统(大三上学期课程设计)
阿西吧.自从学会使用框架.再看以前写的.我真的是要死了.项目用的还不是maven.整理项目能给我搞死.更要命的是这个项目还是用eclipse写的.数据库还是SQL server.阿西吧 这个系统代码不 ...
- 最近无聊搭建一个齐博X1的下载页面
https://layui.wanxiangsucai.com/ 用layui官方镜像站的模版 改了个齐博X1的下载页面 https://x1.wanxiangsucai.com/ 哈哈哈!!! 还有 ...
- linux下开机启动443程序无法访问解决方法
前言:最近,有一个项目需要用到开机自动启动程序,所以就研究了一下,环境为redhat8,程序是node,使用forever来进行node程序的持久化,程序使用的是443端口,开启的是https 1.把 ...
- 三、Python语法介绍
三.Python语言介绍 3.1.了解Python语言 Python 是1989 年荷兰人 Guido van Rossum (简称 Guido)在圣诞节期间为了打发时间,发明的一门面向对象的解释性编 ...
- pycharm系列---基本配置
自动加入头文件 # _*_ coding: utf-8 _*_ # @Time : ${DATE} ${TIME} # @Author : xiechunhui # @Version:V 0.1 # ...
- Go语言核心36讲07
在前文中,我解释过代码块的含义.Go语言的代码块是一层套一层的,就像大圆套小圆. 一个代码块可以有若干个子代码块:但对于每个代码块,最多只会有一个直接包含它的代码块(后者可以简称为前者的外层代码块). ...
- chronyd为隔离网络设置时间同步
参考链接:https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_basic ...
- linux驱动移植
1.1 开发前准备 1.1.1 Linux 驱动(面向对象) 1).Linux 驱动框架 思想:写驱动的时候,只提供操作硬件设备的函数接口 文件存放磁盘: open ,read ,write ,clo ...
- Mybatis-plus - ActiveRecord 模式CRUD
什么是ActiveRecord模式 ActiveRecord 也属于 ORM 层,由 Rails 最早提出,遵循标准的 ORM 模型:表映射到记录,记录映射到对象,字段映射到对象属性.配合遵循的命名和 ...
- python3获取列表逆序的五种方式
前言 我们将这几种方式分为两类,一种是对列表本身进行操作,改变对应内存中的值,另一种是带有返回值的,相当于拷贝了一份 对列表内存中进行操作 sort() 函数 a = [1,2,3,4] a.sort ...