音频压缩编码的本质是感知编码,利用感知模型去除不敏感的声音数据,同时保证声音质量不会有明显下降。它采用子带编码技术,根据心理声学模型获得不同子带的听觉掩蔽阈值,并对每个子带的取样值进行动态量化。
(1)声音信号中的“冗余”信息:
频域:非均匀功率密度谱, 低频能量高,高频能量低。
时域:信息冗余度主要表现在幅度非均匀分布,即不同幅度的样值出现的概率不同,小幅度的样值比大幅度样值出现的概率高。
(2)声音中存在与听觉无关的“不相关”部分:
利用人耳听觉的心理声学模型,对于人耳感觉不到的不相关部分不编码、不传送,以达到数据压缩的目的。
人耳听觉系统存在一个听觉阈值电平,低于该电平的声音听不到。听觉阈值的大小随声音频率的的改变而改变。一个人是否能听到声音取决于声音的频率,以及声音的幅度是否高于该频率下的听觉阈值。
一个较弱的声音的听觉感受被另一个较强的声音影响的现象称为人耳的听觉掩蔽效应。听不到的叫被掩蔽声,起掩蔽作用的叫掩蔽声。掩蔽效应分为频域掩蔽和时域掩蔽。
频域掩蔽:一个强纯音会掩蔽在其附近同时发声的弱纯音,这种特性称为频域掩蔽,也称同时掩蔽。音调音的掩蔽阈的宽度随频率而变化;掩蔽曲线不对称,高频段一侧的曲线斜率缓些;低频音容易对高频音产生掩蔽。
时域掩蔽:在时间上相邻的声音之间也有掩蔽现象。时域掩蔽又分为超前掩蔽和滞后掩蔽。
当某个纯音被以它为中心频率、具有一定带宽的连续噪声所掩蔽时,该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽称为临界频带。它是心理声学模型的基本单位。
人类听觉系统大致等效于一个在0Hz到20KHz频率范围内,由25个重叠的带通滤波器组成的滤波器组。人耳不能区分同一频带内同时发生的不同声音,人耳频带被称为临界频带。500Hz以下临界频带的带宽大约是100Hz,500Hz以上呈线性增加。
掩蔽效应在一定频率范围内不随带宽增大而改变,直至超过某个频率值。
使用一组带通滤波器把输入音频信号的频带分成若干个连续的频段,每个频段称为子带。对每个子带中的音频信号采用单独的编码方案去编码。在信道上传送时,将每个子带的代码复合起来。在接收端解码时,将每个子带的代码单独解码,然后把它们组合起来,还原出原来的音频信号。
①比特因子的取值及编码
对各个子带每12个样点进行一次比例因子计算。先定出12个样点中绝对值的最大值。查比例因子表中比这个最大值大的最小值作为比例因子。用6比特表示。
第2层的一帧对应36个子带样值,是第1层的三倍,原则上要传三个比例因子。为了降低比例因子的传输码率, 采用了利用人耳时域掩蔽特性的编码策略。
每帧中每个子带的三个比例因子被一起考虑,划分成特定的几种模式。根据这些模式,1个、2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如果一个比例因子和下一个只有很小的差别,就只传送大 的一个,这种情况对于稳态信号经常出现。
②比特分配及编码
在调整到固定的码率之前,先确定可用于样值编码的有效比特数,这个数值取决于比例因子、比例因子选择信息、比特分配信息以及辅助数据所需比特数。
对每个子带计算掩蔽-噪声比MNR,是信噪比SNR – 信掩比 SMR,即:MNR = SNR – SMR,使整个一帧和每个子带的总噪声-掩蔽比最小。这是一个循环过程,每一次循环使获益最大的子带的量化级别增加一级,当然所用比特数不能超过一帧所能提供的最大数目。
③子带样值的量化及编码
输入以12个样本为一组,每组样本经过时间-频率变换 之后进行一次比特分配并记录一个比例因子(scale factor) 。比特分配信息告诉解码器每个样本由几位表示,比例因子用6比特表示,解码器使用这个6比特的比例因子乘逆量化器的每个输出样本值,以恢复被量化的子带值。比例因子的作用是充分利用量化器的量化范围,通过比特分配和比例因子相配合,可以表示动态范围超过120dB的样本 。
层Ⅰ每帧含384个样本数据,每帧由32个子带分别输出的12个样本值组成。以48KHz采样,则一帧长为:32X12X20.83us=8ms。
层Ⅱ每帧包含1152个样本。低、中、高频段对比特分配不同,分别是4、3、2比特。比特流中增加的比特因子选择信息域提供是否需要及如何共享比例因子等信息。
感知音频编码的设计思想是:一个矛盾两条线。
一个矛盾:时域分析和频域分析的矛盾->提高时域,放弃频域
两条线:根据基本原理得出两条路线的编码图(MUSICAM编码器):
1、输出音频采样率和目标码率
if(frameNum==20)
{
fprintf(outinfo,"采样率:%.1fkhz\n",s_freq[header.version][header.sampling_frequency]);
fprintf(outinfo,"目标码率:%dMbps\n",bitrate[header.version][header.bitrate_index])
}
2、输出某帧所分配的比特数、比例因子和比特分配结果
if (frameNum == 20)
{
fprintf(outinfo,"该帧所分配的比特数:%d\n", adb);
fprintf(outinfo, "比例因子为:\n"); //输出比例因子
for (ch = 0; ch < nch; ch++)//声道
{
fprintf(outinfo, "channel[%2d] \n", ch + 1);
for (sb = 0; sb < frame.sblimit; sb++) //子带
{
fprintf(outinfo, "subband[%2d]: ", sb + 1);
for (gr = 0; gr < 3; gr++)
{
fprintf(outinfo, "%2d\t", scalar[ch][gr][sb]);
}
fprintf(outinfo, "\n");
}
}
}
if (frameNum == 20)
{
fprintf(outinfo, "\n比特分配结果:\n"); //输出比特分配结果
int ch, sb;
for (ch = 0; ch < nch; ch++)
{
fprintf(outinfo, "channel[%2d] \n", ch + 1); //
for (sb = 0; sb < frame.sblimit; sb++)
{
fprintf(info, "subband[%2d]:%2d\n", sb, bit_alloc[ch][sb]);
}
}
}
1、从比例因子输出结果可以看出,同一子带3个比例因子很接近,可以压缩很多的冗余数据。
2、从帧比特分配结果可以看出,越高频比特数分配得越少。