MPG音频编码
一.实验原理
输入声音信号经过一个多相滤波器组,变换到多个子带。同时经过“心理声学模型”计算以频率为自变量的噪声掩蔽阈值。量化和编码部分用信掩比SMR决定分配给子带信号的量化位数,使量化噪声<掩蔽域值。最后通过数据帧包装将量化的子带样本和其它数据按照规定的帧格式组装成比特数据流。
模块分析
1.多相滤波器组(Polyphase Filter Bank):将PCM样本变换到32个子带的频域信号,如果输入的采样频率为48kHz,那么子带的频率宽度为48/(2*32)=0.75Hz
2.比例因子的取值和编码
*对各个子带每12个样点进行一次比例因子计算。先定出12个样点中绝对值的最大值。查比例因子表中比这个最大值大的最小值作为比例因子。用6比特表示。
*第2层的一帧对应36个子带样值,是第1层的三倍,原则上要传三个比例因子。每帧中每个子带的三个比例因子被一起考虑,划分成特定的几种模式。根据这些模式,1个、2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如果一个比例因子和下一个只有很小的差别,就只传送大的一个,这种情况对于稳态信号经常出现。
3.1024点FFT
引入FFT补偿频率分辨率不足的问题。
4.心理声学模型(Psychoacoustic Model):计算信号中不可听觉感知的部分,计算噪声遮蔽效应
*听觉系统中存在一个听觉阈值电平,低于这个电平的声音信号就听不到,听觉阈值的大小随声音频率的改变而改变。
一个人是否听到声音取决于声音的频率,以及声音的幅度是否高于这种频率下的听觉阈值。听觉掩蔽特性即听觉阈值电平是自适应的,会随听到的不同频率声音而发生变化。
一个人是否听到声音取决于声音的频率,以及声音的幅度是否高于这种频率下的听觉阈值。听觉掩蔽特性即听觉阈值电平是自适应的,会随听到的不同频率声音而发生变化。
*利用心理声学模型可以消除更多的冗余数据,人耳听不见的部分和引入的低于听觉阈值量化噪声不编码,主要声音成分用较多的比特数表示,从而获得更大的压缩效率。
5.比特分配器(Bit Allocator):根据心理声学模型的计算结果,为每个子带信号分配比特数
*在调整到固定的码率之前
先确定可用于样值编码的有效比特数,这个数值取决于比例因子、比例因子选择信息、比特分配信息以及辅助数据所需比特数。
*比特分配的过程
对每个子带计算掩蔽-噪声比MNR,即:MNR = SNR –SMR 其中SNR是信噪比 ,SMR是信掩比;对最低MNR的子带分配比特,使获益最大的子带的量化级别增加一级;重新计算分配了更多比特子带的MNR,循环,直到没有比特可用。
先确定可用于样值编码的有效比特数,这个数值取决于比例因子、比例因子选择信息、比特分配信息以及辅助数据所需比特数。
*比特分配的过程
对每个子带计算掩蔽-噪声比MNR,即:MNR = SNR –SMR 其中SNR是信噪比 ,SMR是信掩比;对最低MNR的子带分配比特,使获益最大的子带的量化级别增加一级;重新计算分配了更多比特子带的MNR,循环,直到没有比特可用。
6.装帧(Frame Creation):产生MPEG-I兼容的比特流
二.实验要求
输出音频的采样率和目标码率
选择某个数据帧,输出该帧所分配的比特数、比例因子、比特分配结果
三.关键代码
m2aenc.c
int main (int argc, char **argv)
{...//add 7.1
FILE *output;
char temp[50] = "frame_infomation.txt";
output = fopen(temp, "w");
if (output == NULL)
{
printf("Creating output txt file failed.\n");
exit(1);
}
//end
......
#else
//add 7.1
if(frameNum==50)
{
fprintf(output,"sampling rate=%.1f khz\n",s_freq[header.version][header.sampling_frequency]);
fprintf(output,"bits rate=%d kbps\n", bitrate[header.version][header.bitrate_index]);
fprintf(output,"the %d frame\n",frameNum);
fprintf(output,"available bits num=%d\n",adb);
fprintf(output,"scale factors:\n");
for(k=0;k<nch;k++)
{
fprintf(output,"channel[%d]\n",k);
for(i=0;i<frame.sblimit;i++)
{
fprintf(output,"subband[%d]:",i);
for(t=0;t<3;t++)
{
fprintf(output,"%d\t",scalar[k][t][i]);
}
fprintf(output,"\n");
}
}
}
//add end
transmission_pattern (scalar, scfsi, &frame);
main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);
//add 7.1
if(frameNum==50)
{
int k,i;
fprintf(output,"bits allocation:\n");
for(k=0;k<nch;k++)
{
fprintf(output,"channel[%d]\n",k);
for(i=0;i<frame.sblimit;i++)
fprintf(output,"subband[%d]:%d\n",i,bit_alloc[k][i]);
}
}
//add end
if (error_protection)
CRC_calc (&frame, bit_alloc, scfsi, &crc);
encode_info (&frame, &bs);
if (error_protection)
encode_CRC (crc, &bs);
encode_bit_alloc (bit_alloc, &frame, &bs);
encode_scale (bit_alloc, scfsi, scalar, &frame, &bs);
subband_quantization (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,
*subband, &frame);
sample_encoding (*subband, bit_alloc, &frame, &bs);
#endif
四.实验结果
结论:
1.原pcm文件4688kB,压缩之后1173kB,压缩比达到4.0左右。
2.实验原理部分我们提到过,每帧中每个子带的三个比例因子被一起考虑,划分成特定的几种模式。根据这些模式,1个、2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如果一个比例因子和下一个只有很小的差别,就只传送大的一个,这种情况对于稳态信号经常出现。.观察每个子带输出的3个比特因子,非常接近。前面的算法可行,并且可以有效降低传输码率。
3.在低频子带中用较小的量化阶、较多的量化级数,即分配较多的位数来表示样本值。而话音中的摩擦音和类似噪声的声音,通常出现在高频子带中,对它分配较少的位数。这里最后几个高频子带分配的位数都是0。