实验原理
注意这两条线是不同的处理方向
1.子带滤波 提高时间分辨率
2.fft转变为频域方面进行分析
3.心理声学模型,依据人耳听觉阈值和听觉掩蔽特性建立
4.比例因子提取、选择,每个子带的12个样点为一个数据块,则一个子带含有3个数据块,将这三个数据块的比例因子进行提取并比较
5.动态比特分配,根据码率和心理声学模型,为子带分配最合理的量化比特数,使整帧和每个子带的噪掩比NMR最小的算法
心理声学模型理解
1.频域掩蔽 一个强纯音会掩蔽在其频域上附近同时发声的弱纯音,这称为频域掩蔽
2.时域掩蔽效应 时间上相邻的声音也会有掩蔽现象,即一个时域上强音对附近的其他弱音有掩蔽效应。分为超前掩蔽和滞后掩蔽。
3.对每个子带计算掩蔽-噪声比MNR,是信噪比SNR与信掩比SMR之差,
MNR = SNR–SMR
噪声-掩蔽比(noise-to-mask ratio, NMR):NMR = SMR – SNR (dB),每次给掩噪比最小的子带增加bit数
代码分析
1.输出音频的采样率和目标码率
void print_config (frame_info * frame, int *psy, char *inPath,
char *outPath)
{
frame_header *header = frame->header;
if (glopts.verbosity == 0)
return;
fprintf (stderr, "--------------------------------------------\n");
fprintf (stderr, "Input File : '%s' %.1f kHz\n",
(strcmp (inPath, "-") ? inPath : "stdin"),
s_freq[header->version][header->sampling_frequency]);
fprintf (stderr, "Output File: '%s'\n",
(strcmp (outPath, "-") ? outPath : "stdout"));
fprintf (stderr, "%d kbps ", bitrate[header->version][header->bitrate_index]);
fprintf (stderr, "%s ", version_names[header->version]);
if (header->mode != MPG_MD_JOINT_STEREO)
fprintf (stderr, "Layer II %s Psycho model=%d (Mode_Extension=%d)\n",
mode_names[header->mode], *psy, header->mode_ext);
else
fprintf (stderr, "Layer II %s Psy model %d \n", mode_names[header->mode],
*psy);
fprintf (stderr, "[De-emph:%s\tCopyright:%s\tOriginal:%s\tCRC:%s]\n",
((header->emphasis) ? "On" : "Off"),
((header->copyright) ? "Yes" : "No"),
((header->original) ? "Yes" : "No"),
((header->error_protection) ? "On" : "Off"));
fprintf (stderr, "[Padding:%s\tByte-swap:%s\tChanswap:%s\tDAB:%s]\n",
((glopts.usepadbit) ? "Normal" : "Off"),
((glopts.byteswap) ? "On" : "Off"),
((glopts.channelswap) ? "On" : "Off"),
((glopts.dab) ? "On" : "Off"));
if (glopts.vbr == TRUE)
fprintf (stderr, "VBR Enabled. Using MNR boost of %f\n", glopts.vbrlevel);
fprintf(stderr,"ATH adjustment %f\n",glopts.athlevel);
fprintf (stderr, "--------------------------------------------\n");
}
2.输出某数据帧的相关内容
int frameNum = 0;
int spec_frameNum = 1;//newly added 指定的帧数
int main (int argc, char **argv)
......
FILE* result;
result = fopen("output_result.txt", "w");
if (result == NULL){
printf("error opening txt file.");
system("pause");
exit(-1);}//newly added
if(frameNum == spec_frameNum)
fprintf (stderr, "[%4u]\r", frameNum);
while (get_audio (musicin, buffer, num_samples, nch, &header) > 0) {
if (glopts.verbosity > 1)
if (++frameNum % 10 == 0)
fprintf (stderr, "[%4u]\r", frameNum);
fflush (stderr);
output = (frameNum == spec_frame);
win_buf[0] = &buffer[0][0];
win_buf[1] = &buffer[1][0];
adb = available_bits (&header, &glopts);//number of available bits
//输出可用比特数
if(output)
fprintf(result,"可用比特数:%d\n",adb);//newly added
......
scale_factor_calc (*sb_sample, scalar, nch, frame.sblimit);//计算比例因子scalar
pick_scale (scalar, &frame, max_sc);
if (frame.actual_mode == MPG_MD_JOINT_STEREO) {
/* this way we calculate more mono than we need */
/* but it is cheap */
combine_LR (*sb_sample, *j_sample, frame.sblimit);//各个子带左右声道结合,结合后的为j_sample
scale_factor_calc (j_sample, &j_scale, 1, frame.sblimit);//计算比例因子j_scale
}
if (frameNum == spec_frameNum)
{
//输出比例因子
fprintf(result, "比例因子:\n");
for (int k = 0; k < nch; k++)//声道
{
fprintf(result, "声道:%d:\n", k + 1);
for (int i = 0; i < SBLIMIT; i++)//子带三个比例因子
{
fprintf(result, "子带:%d:\t", i);
for (int j = 0; j < 3; j++)
{
fprintf(result, "%d\t", scalar[k][j][i]);
}
fprintf(result, "\n");
}
}
}
......
transmission_pattern (scalar, scfsi, &frame);
main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);
//输出比特分配结果
if (frameNum == spec_frameNum)
{
fprintf(result, "比特分配结果\n");
for (int k = 0; k < nch; k++)//声道
{
fprintf(result, "声道%d:\n", k + 1);
for (int i = 0; i < SBLIMIT; i++)//每个子带有一个比特分配结果
{
fprintf(result, "子带%d:\t", i);
fprintf(result, "%d\n", bit_alloc[k][i]);
}
}
}
......
fclose(result);
结果分析
频带频率越高分配到的比特数越少,与实验原理一致