一、MPEG音频编码原理
1.1 基本思想
分析信号,去掉不能被感知的部分【声音压缩算法可以确立这种特性的模型来取消更多的冗余数据】
- 子带分析滤波器组:使信号具有高的时间分辨率【短暂冲击信号情况下,编码的声音信号具有足够高的质量】
- FFT运算:使信号具有高的频率分辨率
- 比特分配:低频子带分配较多的位数【保护音调和共振峰的结构】;高频自带分配较少的位数【摩擦音和类似噪声的声音】
1.2 心理声学模型(Psychoacoustic model)
- 生理(Physiological)感知极限(传感极限)
- 心理(Psychological)感知极限(信号处理极限)
1.2.1 听觉阈值
听觉系统中存在一个听觉阈值电平,低于这个电平的声音信号就听不到
- 听觉阈值的大小随声音频率的改变而改变
- 一个人是否听到声音取决于声音的频率,以及声音的幅度是否高于这种频率下的听觉阈值。
1.2.2 频域掩蔽
听觉阈值电平是自适应的,会随听到的不同频率声音而发生变化
如果有多个频率成分的复杂信号存在,那么频谱的总掩蔽阈值与频率的关系取决于各掩蔽音的强度、频率和它们之间的距离。
1.3 临界频带(Critical Band)
临界频带是指当某个纯音被以它为中心频率、且具有一定带 宽的连续噪声所掩蔽时,如果该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽为临界频带宽度。
1 B a r k = { f 100 , f o r f r e q u e n c i e s f < 500 H z 9 + 4 l o g ( f 1000 ) , f o r f r e q u e n c i e s f ≥ 500 H z 1 Bark=\left\{ \begin{aligned} &\frac{f}{100},&&for frequencies&& f<500Hz \\ &9+4log(\frac{f}{1000}),&& for frequencies&& f \geq 500Hz\\ \end{aligned} \right. 1Bark=⎩⎪⎪⎨⎪⎪⎧100f,9+4log(1000f),forfrequenciesforfrequenciesf<500Hzf≥500Hz
1.4 人耳听觉系统
人类听觉系统大致等效于一个信号通过一组并联的不同中心频率的带通滤波器。
- 听音者在噪声中听某一纯音信号时,只启用中心频率与信号频率相同的那个听觉滤波器。纯音信号通过该滤波器,而噪声信号只有通带范围内的部分信号能通过,通带以外的频率成分则被抑制,只有通过该滤波器的噪声才对掩蔽起作用。
- 聆听复音时启动多个听觉滤波器。听觉能够计算各滤波器输出端的信噪比。当信噪比达到或者超过听阈因子时,即可听到该频率成分。
1.5 掩蔽效果的加和
Lutfi对多个掩蔽音同时存在时的综合掩蔽效果进行了研究: 每个掩蔽音的掩蔽效果先独立变换然后再线性相加。
F ( M A B = F ( M A ) + F ( M B ) F(M_{AB}=F(M_A)+F(M_B) F(MAB=F(MA)+F(MB) F ( M A ) = ( 1 0 M A / 10 ) p F(M_A)=(10^{M_A/10})^p F(MA)=(10MA/10)p
- 当两个信号重叠并落在一个临界频带中时,二者的掩蔽分量可以线 性相加。
- 对于复杂音频信号可将其频谱分割成一系列离散段,每段就是一个掩蔽信号。各掩蔽音互不重叠,即以一个临界带为单位。各掩蔽音的声压级则通过将对应的临界频带上的短时功率谱密度线性相加得到 。
二、MPEG音频压缩编码器
输入声音信号经过一个多相滤波器组,变换到多个子带,同时经过“心理声学模型”计算以频率为自变量的噪声掩蔽阈值。量化和编码部分用信掩比SMR决定分配给子带信号的量化位数,使量化噪声<掩蔽阈值。最后通过数据帧包装 将量化的子带样本和其它数据按照规定的帧格式组装成比特数据流。
2.1 多相滤波器组(Polyphase Filter Bank)
先分成32个相等的子带。
512个输入样本空间的FIFO。
新输入的32个样本在最低端。
多相滤波器组的缺点:
- 等带宽的滤波器组与人类听觉系统的临界频带不对应【在低频区域,单个子带会覆盖多个临界频带。】。
- 滤波器组与其逆过程不是无失真的【但滤波器组引入的误差很小,且听不到】
- 子带间频率有混叠【滤波后的相邻子带有频率混叠现象,一个子带中的信号可以影响相邻子带的输出】
2.2 心理声学模型
MPEG-1标准定义了两个模型。
心理声学模型 1:
- 计算复杂度低
- 但对假设用户听不到的部分压缩太严重
心理声学模型 2:
- 提供了适合Layer 3编码的更多特征
实习实现的模型复杂度取决于所需要的压缩因子。
2.3 量化和编码
2.3.1 比例因子的取值和编码
对各个子带每12个样点进行一次比例因子计算【查表】。
第二层中一帧对应36个子带样值,原则上要传送3个比例因子。
为了降低比例因子的传输码率,每帧中每个子带的三个比例因子被划分成特定的几种模式,根据这些模式,1个、2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如 果一个比例因子和下一个只有很小的差别,就只传送大的一个【这种情况在稳态信号中经常出现】。
2.3.2 比特分配及编码
- 对每个子带计算掩蔽-噪声比MNR M N R = S N R ( 信 噪 比 ) − S M R ( 信 掩 比 ) MNR=SNR(信噪比)-SMR(信掩比) MNR=SNR(信噪比)−SMR(信掩比)
- 使整个一帧和每个子带的总噪声-掩蔽比最小
【循环过程:每一次循环给获益最大的子带分配一个比特】
【第一层 1帧用4比特给每个子带的比特分配信息编码;第二层只在低频段用4比特,高频段用2比特】
比例因子的作用是充分利用量化器的量化范围, 通过比特分配和比例因子相配合,可以表示动态范围超过120dB的样本 。
2.3.3 数据帧包装
以层2为例:
- 帧头(Header):每帧开始的头32个比特,包含有同步和状态比特流信息,在所有层都相同,同步码字为12bit全1码。
- 误码检测CRC:使用一种16bit奇偶校验字,可供在比特流中作检测误码用。
- 声音数据:由比特分配表、比例因子选择信息、比例因子和子带样值组成,其中子带样值是声音数据的最大部分。
- 辅助数据:用作辅助数据比特流。
三、MPEG音频编码器调试
调试的第一步自然是跑通代码弄清楚输入参数。代码在第一次编译的时候有报错,是编译环境的问题,直接复制报错信息google一下就可以解决,在此不进行说明了。
然后运行一下代码,得到如下结果:
按照提示信息所说,必须要输入的就只有输入文件的名字,所以,如下图所示输入命令并得到结果:
3.1 理解程序设计的整体框架
通过main()函数上方的注释可以很方便的知道程序设计的框架。
/************************************************************************
*
* main
*
* PURPOSE: MPEG II Encoder with
* psychoacoustic models 1 (MUSICAM) and 2 (AT&T)//心理声学模型
*
* SEMANTICS: One overlapping frame of audio of up to 2 channels are
* processed at a time in the following order:
* (associated routines are in parentheses)//最多按以下顺序一次处理最多2个通道的一个重叠音频帧
*
* 1. Filter sliding window of data to get 32 subband
* samples per channel.
* (window_subband,filter_subband)//过滤数据滑动窗口以获取每个通道32个子带样本
*
* 2. If joint stereo mode, combine left and right channels
* for subbands above #jsbound#.//如果是联合立体声模式,请为#jsbound#以上的子带组合左右声道
* (combine_LR)
*
* 3. Calculate scalefactors for the frame, and
* also calculate scalefactor select information.//计算比例因子,并计算比例因子选择信息。
* (*_scale_factor_calc)
*
* 4. Calculate psychoacoustic masking levels using selected
* psychoacoustic model.//使用选定的心理声学模型计算心理声学掩蔽电平。
* (psycho_i, psycho_ii)
*
* 5. Perform iterative bit allocation for subbands with low
* mask_to_noise ratios using masking levels from step 4.//使用步骤4中的掩蔽电平,对具有低掩蔽比的子带执行迭代位分配。
* (*_main_bit_allocation)
*
* 6. If error protection flag is active, add redundancy for
* error protection.//若是需要,就添加CRC纠错
* (*_CRC_calc)
*
* 7. Pack bit allocation, scalefactors, and scalefactor select
*headerrmation onto bitstream.//将比特分配,比例因子和比例因子打包到比特流中。
* (*_encode_bit_alloc,*_encode_scale,transmission_pattern)
*
* 8. Quantize subbands and pack them into bitstream//量化子带并将其打包成比特流
* (*_subband_quantization, *_sample_encoding)
*
************************************************************************/
整理成有序列表如下 :
- 对滑动窗口内的音频信号进行了32子带滤波;
- 如果有立体声,就加入左右声道;
- 计算这一帧的比例因子及比例因子选择信息‘
- 使用选定的心理声学模型计算心理声学掩蔽水平;
- 使用步骤4中的掩蔽电平,对具有低掩蔽比的子带执行迭代位分配;
- 若是需要,就添加CRC纠错;
- 将比特分配,比例因子和比例因子信息打包到比特流中;
- 量化子带并将其打包成比特流
音频编码和视频编码不同,没有反馈的机制,只是一条顺序过程走下去,所以比之视频编码来的相对较为容易。
main()函数框架分析:
int main(int argc, char** argv)
{
/********************************以上都是初始化,不需要过多关注***************************************************/
programName = argv[0];
if (argc == 1) /* no command-line args */ //如果命令行没有输入
short_usage();
else
parse_args(argc, argv, &frame, &model, &num_samples, original_file_name,
encoded_file_name);//解析命令行参数
print_config(&frame, &model, original_file_name, encoded_file_name);//输出一些配置信息
/* this will load the alloc tables and do some other stuff */