数据压缩实验六--MPEG
感知音频编码设计思想
MPEG-1 Audio LayerII编码器原理
基本思想:分析信号,去掉不能被感知的部分。
通过子带分析滤波器组使信号具有高的时间分辨率,确保在短暂冲击信号情况下,编码的声音信号具有足够高的质量。
又可以使信号通过FFT运算具有高的频率分辨率,因为掩蔽阈值是从功率谱密度推出来的。
输入声音信号经过一个多相滤波器组,变换到多个子带。同时经过心理声学模型计算以频率为自变量的噪声掩蔽阈值。量化和编码部分用信掩比SMR决定分配给自带信号的量化位数,使量化噪声<掩蔽阈值。最后通过数据帧包装将量化的子带样本和其它数据按照规定的帧格式组装成比特数据流。
多相滤波器组
先分成32个相等的子带。
对每个子带每12个样点进行一次比例因子计算。先定出12个样点中绝对值的最大值。查比例因子表中比这个最大值大的最小值作为比例因子。用6比特表示。
第2层的一帧对应36个子带样值,是第1层的3倍,原则上要上传三个比例因子。为了降低比例因子的传输码率,采用了利用人耳时域掩蔽特性的编码策略。
每帧中每个子带的三个比例因子被一起考虑,划分成特定的几种模式。根据这些模式,1个,2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如果一个比例因子和下一个只有很小的差别,就只传送大的一个,这种情况对稳态信号经常出现。
使用这一算法后,和第1层相比,第2层传输的比例因子平均减少了2个。
多相滤波器组的缺点
等带宽的滤波器组与人类听觉系统的临界频带不对应。在低频区域,单个子带会覆盖多个临界频带。在这种情况下,量化比特数不能兼顾每个临界频带。
心理声学模型
人耳听觉系统大致等效于一个信号通过一组并联的不同中心频率的带通滤波器。
临界频带
临界频带是指当某个纯音被以它为中心频率,且具有一定带宽的连续噪声所掩蔽时,如果该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽为临界频率带宽。
临界频带是研究窄带噪声对纯音掩蔽量的规律时被发现的。
使噪声的中心频率等于信号频率,只改变噪声的带宽同时保持噪声的功率谱密度不变,测试纯音听阈随掩蔽噪声带宽变化的特性。纯音的听阈随掩蔽噪声带宽的增大而增大,在带宽增加到某一特定值之后听阈恒定保持不变。
通常认为从20hz到16khz有25个临界频带,单位为bark,越靠近低频,临界频带越细。
掩蔽值计算
音频信号通常有较为复杂的频谱结构,因此能产生掩蔽阈值的掩蔽音分量也有许多。
掩蔽音与被掩蔽音的组合方式有四种,它们可以分别是乐音信号和窄带信号。
Lutfi对多个掩蔽音同时存在时的综合掩蔽效果进行了研究:每个掩蔽音的掩蔽效果先独立变换再线性相加。
心理声学模型I的具体过程
1.采用512(Layer I)或1024(Layer II)样本窗口
Layer I:每帧384个样本点,512个样本点足够覆盖
Layer II和Layer III:每帧1152个样本点,每帧两次。
2.确定声压级别
3.考虑安静时阈值
也即绝对阈值。在标准中有根据输入PCM信号的采样率编制的“频率,临界频带和绝对阈值”表。此表为多位科学家经多次心理声学实验所得。
4.将音频信号分解为“乐音”和“噪声”部分:因为两种信号的掩蔽能力不同。
根据音频频谱的局部功率最大值确定乐音成分,局部峰值为乐音,然后将本临界频带内的剩余频谱合在一起,组成一个代表噪声频率。
5.音调和非音调掩蔽成分的消除
利用标准中给出的绝对阈值消除被掩蔽的成分;考虑在每个临界频带内,小于0.5bark的距离中只保留最高功率的成分。
6.单个掩蔽阈值的计算
音调成分和非音调成分单个掩蔽阈值根据标准中给出的算法求得。
7.全局掩蔽阈值的计算
还要考虑别的临界频带的影响。一个掩蔽信号会对其它频带上的信号蝉声掩蔽效应。这种掩蔽效应称为掩蔽扩散。
8.每个子带的掩蔽阈值
选择出本子带最小的阈值作为子带阈值。
9.计算每个子带信号信掩比
SMR=信号能量/掩蔽阈值,并将SMR传递给编码单元。
码率分配
LayerI
在调整到固定的码率之前,先确定可用于样值编码的有效比特数,这个数值取决于比例因子,比例因子选择信息,比特分配信息以及辅助数据所需比特数。
算法:使整帧和每个子带的总噪声-掩蔽比最小
噪声-掩蔽比NMR=SMR(信掩比)-SNR(信噪比)
循环,直到没有比特可用:对最高NMR的子带分配比特,使获益最大的子带的量化级别增加一级。重新计算分配了更多比特子带的NMR。(每分配1比特,NMR减小6dB)
装帧
LayerII
与LayerI类似,但对LayerI有增强(装帧,缩放因子表示,量化)
装帧:3组/帧 × 12个样本/子带 × 32个子带/帧 = 1152个样本/帧
缩放因子:每个子带的3个组尽可能共用缩放因子。
量化:根据采样和码率量化,不同子带可以从不同的量化器集合中选择。
实验过程
开始运行程序时,出现如下错误:
需要在项目属性-代码生成-启用函数级链接中将“否”改为“是”。
之后程序就可以顺利运行了。
输出音频的采样率和目标码率
选取一段乐音music.wav
音频的采样率:44.1KHZ
目标码率:192Kbps
某个数据帧的比特数,比例因子,比特分配结果
在common.h中加入TRACE
#define FRAME_TRACE 1
在m2aenc.c中加入如下代码:
#if FRAME_TRACE
FILE* need;
need = fopen("need.txt", "a");
if (frameNum == 3) {
fprintf(need, "采样率=%.1f khz ", s_freq[header.version][header.sampling_frequency]);
fprintf(need, "目标码率=%.d kbps\n", bitrate[header.version][header.bitrate_index]);
fprintf(need, "声道数:%d\n", nch);
fprintf(need, "目前观测第 %d 帧\n", frameNum);
fprintf(need, "本帧比特预算:%d bits\n", adb);
fprintf(need, "\n");
/* 比例因子 */
fprintf(need, "========== 比例因子 ==========\n");
for (ch = 0; ch < nch; ch++) // 每个声道单独输出
{
fprintf(need, "------ 声道%2d ------\n", ch + 1);
for (sb = 0; sb < frame.sblimit; sb++) // 每个子带
{
fprintf(need, "子带[%2d]:\t", sb + 1);
for (int gr = 0; gr < 3; gr++) {
fprintf(need, "%2d\t", scalar[ch][gr][sb]);
}
fprintf(need, "\n");
}
}
fprintf(need, "\n");
/* 比特分配表 */
fprintf(need, "========== 比特分配表 ==========\n"); //输出比特分配结果
for (ch = 0; ch < nch; ch++) {
fprintf(need, "------ 声道%2d ------\n", ch + 1); //按声道分配
for (sb = 0; sb < frame.sblimit; sb++) {
fprintf(need, "子带[%2d]:\t%2d\n", sb + 1, bit_alloc[ch][sb]);
}
fprintf(need, "\n");
}
}
fclose(need);
#endif // FRAME_TRACE
输出的信息在outinfo.txt中
========== 比例因子 ==========
------ 声道 1 ------
子带[ 1]: 9 9 9
子带[ 2]: 14 14 14
子带[ 3]: 17 17 17
子带[ 4]: 23 23 23
子带[ 5]: 28 28 28
子带[ 6]: 23 23 23
子带[ 7]: 22 22 22
子带[ 8]: 21 21 21
子带[ 9]: 27 27 27
子带[10]: 30 30 30
子带[11]: 28 28 28
子带[12]: 27 27 27
子带[13]: 24 24 24
子带[14]: 26 26 23
子带[15]: 21 21 21
子带[16]: 26 23 23
子带[17]: 28 30 30
子带[18]: 30 31 31
子带[19]: 29 29 29
子带[20]: 28 28 28
子带[21]: 29 29 28
子带[22]: 30 30 30
子带[23]: 39 39 39
子带[24]: 54 50 50
子带[25]: 52 52 52
子带[26]: 53 53 53
子带[27]: 51 51 51
子带[28]: 52 52 52
子带[29]: 53 53 53
子带[30]: 52 52 52
========== 比特分配表 ==========
------ 声道 1 ------
子带[ 1]: 8
子带[ 2]: 8
子带[ 3]: 6
子带[ 4]: 9
子带[ 5]: 7
子带[ 6]: 8
子带[ 7]: 7
子带[ 8]: 6
子带[ 9]: 6
子带[10]: 6
子带[11]: 6
子带[12]: 6
子带[13]: 6
子带[14]: 6
子带[15]: 7
子带[16]: 5
子带[17]: 4
子带[18]: 4
子带[19]: 5
子带[20]: 6
子带[21]: 5
子带[22]: 4
子带[23]: 0
子带[24]: 0
子带[25]: 0
子带[26]: 0
子带[27]: 0
子带[28]: 0
子带[29]: 0
子带[30]: 0
选择不同特性的音频文件
选取一段持续噪声noise.wav
========== 比例因子 ==========
------ 声道 1 ------
子带[ 1]: 62 47 42
子带[ 2]: 62 53 47
子带[ 3]: 62 55 44
子带[ 4]: 62 57 42
子带[ 5]: 62 59 44
子带[ 6]: 62 58 45
子带[ 7]: 62 58 47
子带[ 8]: 62 59 50
子带[ 9]: 62 62 46
子带[10]: 62 58 43
子带[11]: 62 62 45
子带[12]: 62 61 52
子带[13]: 62 62 56
子带[14]: 62 61 54
子带[15]: 62 62 53
子带[16]: 62 62 49
子带[17]: 62 60 52
子带[18]: 62 62 55
子带[19]: 62 62 51
子带[20]: 62 62 54
子带[21]: 62 62 56
子带[22]: 62 62 57
子带[23]: 60 60 60
子带[24]: 62 62 57
子带[25]: 62 62 57
子带[26]: 60 60 60
子带[27]: 62 62 58
------ 声道 2 ------
子带[ 1]: 62 49 41
子带[ 2]: 62 52 41
子带[ 3]: 62 54 54
子带[ 4]: 62 58 48
子带[ 5]: 62 59 51
子带[ 6]: 62 61 49
子带[ 7]: 62 61 54
子带[ 8]: 62 58 50
子带[ 9]: 62 57 53
子带[10]: 62 59 52
子带[11]: 62 60 55
子带[12]: 62 60 54
子带[13]: 62 59 54
子带[14]: 62 57 53
子带[15]: 62 62 55
子带[16]: 60 60 60
子带[17]: 62 59 59
子带[18]: 62 58 54
子带[19]: 62 56 56
子带[20]: 62 58 53
子带[21]: 62 59 56
子带[22]: 62 57 57
子带[23]: 62 58 58
子带[24]: 62 60 57
子带[25]: 59 59 59
子带[26]: 61 61 61
子带[27]: 58 58 58
========== 比特分配表 ==========
------ 声道 1 ------
子带[ 1]: 4
子带[ 2]: 3
子带[ 3]: 5
子带[ 4]: 8
子带[ 5]: 7
子带[ 6]: 7
子带[ 7]: 6
子带[ 8]: 4
子带[ 9]: 5
子带[10]: 6
子带[11]: 5
子带[12]: 2
子带[13]: 0
子带[14]: 1
子带[15]: 0
子带[16]: 1
子带[17]: 0
子带[18]: 0
子带[19]: 0
子带[20]: 0
子带[21]: 0
子带[22]: 0
子带[23]: 0
子带[24]: 0
子带[25]: 0
子带[26]: 0
子带[27]: 0
------ 声道 2 ------
子带[ 1]: 5
子带[ 2]: 5
子带[ 3]: 2
子带[ 4]: 6
子带[ 5]: 5
子带[ 6]: 5
子带[ 7]: 3
子带[ 8]: 4
子带[ 9]: 2
子带[10]: 3
子带[11]: 1
子带[12]: 1
子带[13]: 1
子带[14]: 1
子带[15]: 0
子带[16]: 0
子带[17]: 0
子带[18]: 0
子带[19]: 0
子带[20]: 0
子带[21]: 0
子带[22]: 0
子带[23]: 0
子带[24]: 0
子带[25]: 0
子带[26]: 0
子带[27]: 0
选择乐音+噪声mix.wav
========== 比例因子 ==========
------ 声道 1 ------
子带[ 1]: 63 62 31
子带[ 2]: 63 62 31
子带[ 3]: 63 62 38
子带[ 4]: 63 62 37
子带[ 5]: 63 62 37
子带[ 6]: 63 62 40
子带[ 7]: 63 62 45
子带[ 8]: 63 62 45
子带[ 9]: 63 62 41
子带[10]: 63 62 40
子带[11]: 63 62 41
子带[12]: 63 62 42
子带[13]: 63 62 47
子带[14]: 63 62 45
子带[15]: 63 62 43
子带[16]: 63 62 44
子带[17]: 63 62 47
子带[18]: 63 62 49
子带[19]: 63 62 44
子带[20]: 63 62 43
子带[21]: 63 62 48
子带[22]: 63 62 58
子带[23]: 63 62 59
子带[24]: 63 62 58
子带[25]: 61 61 61
子带[26]: 60 60 60
子带[27]: 63 62 58
------ 声道 2 ------
子带[ 1]: 63 62 34
子带[ 2]: 63 62 30
子带[ 3]: 63 62 36
子带[ 4]: 63 62 36
子带[ 5]: 63 62 39
子带[ 6]: 63 62 37
子带[ 7]: 63 62 37
子带[ 8]: 63 62 42
子带[ 9]: 63 62 40
子带[10]: 63 62 42
子带[11]: 63 62 41
子带[12]: 63 62 43
子带[13]: 63 62 43
子带[14]: 63 62 41
子带[15]: 63 62 45
子带[16]: 63 62 46
子带[17]: 63 62 43
子带[18]: 63 62 42
子带[19]: 63 62 44
子带[20]: 63 62 48
子带[21]: 63 62 47
子带[22]: 63 62 53
子带[23]: 63 62 59
子带[24]: 63 62 59
子带[25]: 60 60 60
子带[26]: 63 62 58
子带[27]: 63 62 59
========== 比特分配表 ==========
------ 声道 1 ------
子带[ 1]: 5
子带[ 2]: 5
子带[ 3]: 3
子带[ 4]: 6
子带[ 5]: 6
子带[ 6]: 5
子带[ 7]: 2
子带[ 8]: 2
子带[ 9]: 4
子带[10]: 4
子带[11]: 3
子带[12]: 2
子带[13]: 0
子带[14]: 1
子带[15]: 1
子带[16]: 0
子带[17]: 0
子带[18]: 0
子带[19]: 0
子带[20]: 0
子带[21]: 0
子带[22]: 0
子带[23]: 0
子带[24]: 0
子带[25]: 0
子带[26]: 0
子带[27]: 0
------ 声道 2 ------
子带[ 1]: 4
子带[ 2]: 6
子带[ 3]: 4
子带[ 4]: 7
子带[ 5]: 6
子带[ 6]: 6
子带[ 7]: 6
子带[ 8]: 3
子带[ 9]: 4
子带[10]: 3
子带[11]: 3
子带[12]: 2
子带[13]: 1
子带[14]: 2
子带[15]: 0
子带[16]: 0
子带[17]: 0
子带[18]: 0
子带[19]: 0
子带[20]: 0
子带[21]: 0
子带[22]: 0
子带[23]: 0
子带[24]: 0
子带[25]: 0
子带[26]: 0
子带[27]: 0