分析信号,去掉不能被感知的部分【声音压缩算法可以确立这种特性的模型来取消更多的冗余数据】
听觉系统中存在一个听觉阈值电平,低于这个电平的声音信号就听不到
听觉阈值电平是自适应的,会随听到的不同频率声音而发生变化
如果有多个频率成分的复杂信号存在,那么频谱的总掩蔽阈值与频率的关系取决于各掩蔽音的强度、频率和它们之间的距离。
临界频带是指当某个纯音被以它为中心频率、且具有一定带 宽的连续噪声所掩蔽时,如果该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽为临界频带宽度。
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
人类听觉系统大致等效于一个信号通过一组并联的不同中心频率的带通滤波器。
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
- 当两个信号重叠并落在一个临界频带中时,二者的掩蔽分量可以线 性相加。
- 对于复杂音频信号可将其频谱分割成一系列离散段,每段就是一个掩蔽信号。各掩蔽音互不重叠,即以一个临界带为单位。各掩蔽音的声压级则通过将对应的临界频带上的短时功率谱密度线性相加得到 。
输入声音信号经过一个多相滤波器组,变换到多个子带,同时经过“心理声学模型”计算以频率为自变量的噪声掩蔽阈值。量化和编码部分用信掩比SMR决定分配给子带信号的量化位数,使量化噪声<掩蔽阈值。最后通过数据帧包装 将量化的子带样本和其它数据按照规定的帧格式组装成比特数据流。
先分成32个相等的子带。
512个输入样本空间的FIFO。
新输入的32个样本在最低端。
多相滤波器组的缺点:
MPEG-1标准定义了两个模型。
心理声学模型 1:
心理声学模型 2:
实习实现的模型复杂度取决于所需要的压缩因子。
对各个子带每12个样点进行一次比例因子计算【查表】。
第二层中一帧对应36个子带样值,原则上要传送3个比例因子。
为了降低比例因子的传输码率,每帧中每个子带的三个比例因子被划分成特定的几种模式,根据这些模式,1个、2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如 果一个比例因子和下一个只有很小的差别,就只传送大的一个【这种情况在稳态信号中经常出现】。
比例因子的作用是充分利用量化器的量化范围, 通过比特分配和比例因子相配合,可以表示动态范围超过120dB的样本 。
调试的第一步自然是跑通代码弄清楚输入参数。代码在第一次编译的时候有报错,是编译环境的问题,直接复制报错信息google一下就可以解决,在此不进行说明了。
然后运行一下代码,得到如下结果:
按照提示信息所说,必须要输入的就只有输入文件的名字,所以,如下图所示输入命令并得到结果:
通过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)
*
************************************************************************/
整理成有序列表如下 :
音频编码和视频编码不同,没有反馈的机制,只是一条顺序过程走下去,所以比之视频编码来的相对较为容易。
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 */
hdr_to_frps(&frame);//把从信息头中解压出来的信息加载
nch = frame.nch;
error_protection = header.error_protection;
//while里面是获取的每一帧的信息
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);
win_buf[0] = &buffer[0][0];
win_buf[1] = &buffer[1][0];
adb = available_bits(&header, &glopts);//bit预算
lg_frame = adb / 8;
if (header.dab_extension) {
/* in 24 kHz we always have 4 bytes */
if (header.sampling_frequency == 1)
header.dab_extension = 4;
/* You must have one frame in memory if you are in DAB mode */
/* in conformity of the norme ETS 300 401 http://www.etsi.org */
/* see bitstream.c */
if (frameNum == 1)
minimum = lg_frame + MINIMUM;
adb -= header.dab_extension * 8 + header.dab_length * 8 + 16;
}
{
int gr, bl, ch;
/* New polyphase filter
Combines windowing and filtering. Ricardo Feb'03 */
for (gr = 0; gr < 3; gr++)
for (bl = 0; bl < 12; bl++)
for (ch = 0; ch < nch; ch++)
WindowFilterSubband(&buffer[ch][gr * 12 * 32 + 32 * bl], ch,
&(*sb_sample)[ch][gr][bl][0]);//多相滤波器组
}
scale_factor_calc(*sb_sample, scalar, nch, frame.sblimit);//计算比例因子
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);
scale_factor_calc(j_sample, &j_scale, 1, frame.sblimit);//计算比例因子选择信息
}
if ((glopts.quickmode == TRUE) && (++psycount % glopts.quickcount != 0)) {
/* We're using quick mode, so we're only calculating the model every
'quickcount' frames. Otherwise, just copy the old ones across */
for (ch = 0; ch < nch; ch++) {
for (sb = 0; sb < SBLIMIT; sb++)
smr[ch][sb] = smrdef[ch][sb];
}
}
else
{
/* calculate the psymodel */
//根据心理声学模型计算掩蔽电平
switch (model) {
case -1:
psycho_n1(smr, nch);
break;
case 0: /* Psy Model A */ //心理声学模型A计算掩蔽电平
psycho_0(smr, nch, scalar, (FLOAT)s_freq[header.version][header.sampling_frequency] * 1000);//心理声学模型的输出一定是smr
break;
case 1:
psycho_1(buffer, max_sc, smr, &frame);
break;
case 2:
for (ch = 0; ch < nch; ch++) {
psycho_2(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
}
break;
case 3:
/* Modified psy model 1 */
psycho_3(buffer, max_sc, smr, &frame, &glopts);
break;
case 4:
/* Modified Psycho Model 2 */
for (ch = 0; ch < nch; ch++) {
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
}
break;
case 5:
/* Model 5 comparse model 1 and 3 */
psycho_1(buffer, max_sc, smr, &frame);
fprintf(stdout, "1 ");
smr_dump(smr, nch);
psycho_3(buffer, max_sc, smr, &frame, &glopts);
fprintf(stdout, "3 ");
smr_dump(smr, nch);
break;
case 6:
/* Model 6 compares model 2 and 4 */
for (ch = 0; ch < nch; ch++)
psycho_2(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "2 ");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "4 ");
smr_dump(smr, nch);
break;
case 7:
fprintf(stdout, "Frame: %i\n", frameNum);
/* Dump the SMRs for all models */
psycho_1(buffer, max_sc, smr, &frame);
fprintf(stdout, "1");
smr_dump(smr, nch);
psycho_3(buffer, max_sc, smr, &frame, &glopts);
fprintf(stdout, "3");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_2(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "2");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "4");
smr_dump(smr, nch);
break;
case 8:
/* Compare 0 and 4 */
psycho_n1(smr, nch);
fprintf(stdout, "0");
smr_dump(smr, nch);
for (ch = 0; ch < nch; ch++)
psycho_4(&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,
(FLOAT)s_freq[header.version][header.sampling_frequency] *
1000, &glopts);
fprintf(stdout, "4");
smr_dump(smr, nch);
break;
default:
fprintf(stderr, "Invalid psy model specification: %i\n", model);
exit(0);
}
if (glopts.quickmode == TRUE)
/* copy the smr values and reuse them later */
for (ch = 0; ch < nch; ch++) {
for (sb = 0; sb < SBLIMIT; sb++)
smrdef[ch][sb] = smr[ch][sb];
}
if (glopts.verbosity > 4)
smr_dump(smr, nch);
}
transmission_pattern(scalar, scfsi, &frame);
main_bit_allocation(smr, scfsi, bit_alloc, &adb, &frame, &glopts);//进行比特分配
if (error_protection)
CRC_calc(&frame, bit_alloc, scfsi, &crc);//如果需要就添加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);//将子带打包到比特流中
//后面是一些输出信息,也不需要过多关注
...
exit (0);
}
从流程图来看,MPEG音频编码分为清晰的上下两条线。上面一条线是音频编码的主线部分,下面一条线的本质是为了帮助计算线性量化器的量化比特数。其中,下面一条线最为出彩的部分是心理声学模型的应用,它对去除冗余信息起到了极大的作用。
要感知时域的变化,就要增加时域的分辨力,但同时就会对频域的分辨力有所限制,反之亦然,时域分辨力和频域分辨力有着天然的矛盾,我们所能做的就是这两者中取一个中间方案。
临界频带的概念在上文理论部分已经进行过说明,在此不再进行赘述。
在上文中已经讲解过比例因子的计算过程,下面是其实现代码:
void scale_factor_calc(double sb_sample[][3][SCALE_BLOCK][SBLIMIT],
unsigned int scalar[][3][SBLIMIT], int nch,
int sblimit)
{
//scalar就是得到的比例因子
/* Optimized to use binary search instead of linear scan through the
scalefactor table; guarantees to find scalefactor in only 5
jumps/comparisons and not in {0 (lin. best) to 63 (lin. worst)}.
Scalefactors for subbands > sblimit are no longer computed.
Uses a single sblimit-loop.
Patrick De Smet Oct 1999.
*/
int k, t;
/* Using '--' loops to avoid possible "cmp value + bne/beq" compiler */
/* inefficiencies. Below loops should compile to "bne/beq" only code */
for (k = nch; k--;)
for (t = 3; t--;) {
int i;
for (i = sblimit; i--;) {//寻找子带中的最大值
int j;
unsigned int l;
register double temp;
unsigned int scale_fac;
/* Determination of max. over each set of 12 subband samples: */
/* PDS TODO: maybe this could/should ??!! be integrated into */
/* the subband filtering routines? */
register double cur_max = fabs(sb_sample[k][t][SCALE_BLOCK - 1][i]);
for (j = SCALE_BLOCK - 1; j--;) {
if ((temp = fabs(sb_sample[k][t][j][i])) > cur_max)
cur_max = temp;
}
/* PDS: binary search in the scalefactor table: */
/* This is the real speed up: */
for (l = 16, scale_fac = 32; l; l >>= 1) {//查找比例因子表中比这个最大值大的最小值作为比例因子
if (cur_max <= multiple[scale_fac])
scale_fac += l;
else
scale_fac -= l;
}
if (cur_max > multiple[scale_fac])
scale_fac--;
scalar[k][t][i] = scale_fac;//得到比例因子
}
}
}
掩蔽值的计算是通过大量实验得到的经验计算函数,并没有什么严密的数学推导,是实验结果。下面是以心理声学模型A为例的掩蔽值计算代码:
void psycho_0(double SMR[2][SBLIMIT], int nch, unsigned int scalar[2][3][SBLIMIT], FLOAT sfreq) {
int ch, sb, gr;
int minscaleindex[2][SBLIMIT]; /* Smaller scale indexes mean bigger scalefactors */
//较小的指标意味着较大的比例因子
static FLOAT ath_min[SBLIMIT];
int i;
static int init = 0;
if (!init) {
FLOAT freqperline = sfreq / 1024.0;
for (sb = 0; sb < SBLIMIT; sb++) {
ath_min[sb] = 1000; /* set it huge */
}
/* Find the minimum ATH in each subband */
//在每个子带中找到最小的ATH
for (i = 0; i < 512; i++) {
FLOAT thisfreq = i * freqperline;
FLOAT ath_val = ATH_dB(thisfreq, 0);
if (ath_val < ath_min[i >> 4])
ath_min[i >> 4] = ath_val;
}
init++;
}
/* Find the minimum scalefactor index for each ch/sb */
//找到这32个子带中最小的比例因子
for (ch = 0; ch < nch; ch++)
for (sb = 0; sb < SBLIMIT; sb++)
minscaleindex[ch][sb] = scalar[ch][0][sb];
for (ch = 0; ch < nch; ch++)
for (gr = 1; gr < 3; gr++)
for (sb = 0; sb < SBLIMIT; sb++)
if (minscaleindex[ch][sb] > scalar[ch][gr][sb])
minscaleindex[ch][sb] = scalar[ch][gr][sb];
/* Oh yeah. Fudge the hell out of the SMR calculations
by combining the scalefactor table index and the min ATH in that subband
There are probably more elegant/correct ways of combining these values,
but who cares? It works pretty well
MFC Mar 03 */
for (ch = 0; ch < nch; ch++)
for (sb = 0; sb < SBLIMIT; sb++)
SMR[ch][sb] = 2.0 * (30.0 - minscaleindex[ch][sb]) - ath_min[sb];
}
比特分配的具体过程也已经在上文原理部分中有过提及,不再详述。以下是main()函数中实现码率分配的函数体定义和关键代码解释:
void main_bit_allocation(double perm_smr[2][SBLIMIT],
unsigned int scfsi[2][SBLIMIT],
unsigned int bit_alloc[2][SBLIMIT], int* adb,
frame_info* frame, options* glopts)
{
...
//以上都是初始化,不需要过多关注
/* decide on which bit allocation method to use */
if (glopts->vbr == FALSE) {
/* Just do the old bit allocation method */
noisy_sbs = a_bit_allocation(perm_smr, scfsi, bit_alloc, adb, frame);
}
else {
/* do the VBR bit allocation method */
frame->header->bitrate_index = lower;
*adb = available_bits(frame->header, glopts);
{
int brindex;
int found = FALSE;
/* Work out how many bits are needed for there to be no noise (ie all MNR > 0.0 + VBRLEVEL) */
int req =
VBR_bits_for_nonoise(perm_smr, scfsi, frame, glopts->vbrlevel);
/* Look up this value in the bitrateindextobits table to find what bitrate we should use for
this frame */
for (brindex = lower; brindex <= upper; brindex++) {
if (bitrateindextobits[brindex] > req) {
/* this method always *overestimates* the bits that are needed
i.e. it will usually guess right but
when it's wrong it'll guess a higher bitrate than actually required.
e.g. on "messages from earth" track 6, the guess was
wrong on 75/36341 frames. each time it guessed higher.
MFC Feb 2003 */
guessindex = brindex;
found = TRUE;
break;
}
}
/* Just for sanity */
if (found == FALSE)
guessindex = upper;
}
frame->header->bitrate_index = guessindex;
*adb = available_bits(frame->header, glopts);
/* update the statistics */
vbrstats[frame->header->bitrate_index]++;
if (glopts->verbosity > 2) {
/* print out the VBR stats every 1000th frame */
static int count = 0;
int i;
if ((count++ % 1000) == 0) {
for (i = 1; i < 15; i++)
fprintf(stdout, "%4i ", vbrstats[i]);
fprintf(stdout, "\n");
}
/* Print out *every* frames bitrateindex, bits required, and bits available at this bitrate */
if (glopts->verbosity > 5)
fprintf(stdout,
"> bitrate index %2i has %i bits available to encode the %i bits\n",
frame->header->bitrate_index, *adb,
VBR_bits_for_nonoise(perm_smr, scfsi, frame,
glopts->vbrlevel));
}
noisy_sbs =
VBR_bit_allocation(perm_smr, scfsi, bit_alloc, adb, frame, glopts);
}
}
通过调试可以发现,本实验使用的比特分配的函数是a_bit_allocation,以下是这个函数体的定义和关键代码解释:
int a_bit_allocation(double perm_smr[2][SBLIMIT],
unsigned int scfsi[2][SBLIMIT],
unsigned int bit_alloc[2][SBLIMIT], int* adb,
frame_info* frame)
{
int i, min_ch, min_sb, oth_ch, k, increment, scale, seli, ba;
int bspl, bscf, bsel, ad, bbal = 0;
double mnr[2][SBLIMIT];
char used[2][SBLIMIT];
int nch = frame->nch;
int sblimit = frame->sblimit;
int jsbound = frame->jsbound;
al_table* alloc = frame->alloc;
static char init = 0;
static int banc = 32, berr = 0;
static int sfsPerScfsi[] = { 3, 2, 1, 2 }; /* lookup # sfs per scfsi */
if (!init) {
init = 1;
if (frame->header->error_protection)
berr = 16; /* added 92-08-11 shn */
}
for (i = 0; i < jsbound; ++i)
bbal += nch * (*alloc)[i][0].bits;
for (i = jsbound; i < sblimit; ++i)
bbal += (*alloc)[i][0].bits;
*adb -= bbal + berr + banc;
ad = *adb;
for (i = 0; i < sblimit; i++)
for (k = 0; k < nch; k++) {
mnr[k][i] = snr[0] - perm_smr[k][i];
bit_alloc[k][i] = 0;
used[k][i] = 0;
}
bspl = bscf = bsel = 0;
do {
/* locate the subband with minimum SMR */
//找到拥有最大MNR的子带
maxmnr(mnr, used, sblimit, nch, &min_sb, &min_ch);
if (min_sb > -1) { /* there was something to find */
/* find increase in bit allocation in subband [min] */
//计算拥有最大MNR的子带需要分配多少比特位才不是最大
increment =
SCALE_BLOCK * ((*alloc)[min_sb][bit_alloc[min_ch][min_sb] + 1].group *
(*alloc)[min_sb][bit_alloc[min_ch][min_sb] + 1].bits);
if (used[min_ch][min_sb])
increment -=
SCALE_BLOCK * ((*alloc)[min_sb][bit_alloc[min_ch][min_sb]].group *
(*alloc)[min_sb][bit_alloc[min_ch][min_sb]].bits);
/* scale factor bits required for subband [min] */
oth_ch = 1 - min_ch; /* above js bound, need both chans */
if (used[min_ch][min_sb])
scale = seli = 0;
else { /* this channel had no bits or scfs before */
seli = 2;
scale = 6 * sfsPerScfsi[scfsi[min_ch][min_sb]];
if (nch == 2 && min_sb >= jsbound) {
/* each new js sb has L+R scfsis */
seli += 2;
scale += 6 * sfsPerScfsi[scfsi[oth_ch][min_sb]];
}
}
//检查剩下的可用比特位是否能够给出足够的比特位
/* check to see enough bits were available for */
/* increasing resolution in the minimum band */
if (ad >= bspl + bscf + bsel + seli + scale + increment) {
//如果够的话就给这个子带分配比特
ba = ++bit_alloc[min_ch][min_sb]; /* next up alloc */
bspl += increment; /* bits for subband sample */
bscf += scale; /* bits for scale factor */
bsel += seli; /* bits for scfsi code */
used[min_ch][min_sb] = 1; /* subband has bits */
mnr[min_ch][min_sb] =
-perm_smr[min_ch][min_sb] + snr[(*alloc)[min_sb][ba].quant + 1];
/* Check if subband has been fully allocated max bits */ //检查该子带已分配的比特数是否已经到达了最大值
if (ba >= (1 << (*alloc)[min_sb][0].bits) - 1)
used[min_ch][min_sb] = 2; /* don't let this sb get any more bits */
//如果已分配的比特数到达了最大值,那么就不能给他分配比特了
}
else
used[min_ch][min_sb] = 2; /* can't increase this alloc */ //不能分配比特位
if (min_sb >= jsbound && nch == 2) {
/* above jsbound, alloc applies L+R */
ba = bit_alloc[oth_ch][min_sb] = bit_alloc[min_ch][min_sb];
used[oth_ch][min_sb] = used[min_ch][min_sb];
mnr[oth_ch][min_sb] =
-perm_smr[oth_ch][min_sb] + snr[(*alloc)[min_sb][ba].quant + 1];
}
}
} while (min_sb > -1); /* until could find no channel */
/* Calculate the number of bits left */
//计算剩下的比特位的数目
ad -= bspl + bscf + bsel;
*adb = ad;
for (k = 0; k < nch; k++)
for (i = sblimit; i < SBLIMIT; i++)
bit_alloc[k][i] = 0;
return 0;
}
先去原代码的输出函数中看看有没有需要的数据,可以发现音频采样率和目标码率都已经被输出了:
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");
}
由上图可发现,音频的采样率为44.1KHz,目标码率为192Kbps。
在进入循环前打开文件,main()函数末尾关闭文件。
int main(int argc, char** argv)
{
...
/* this will load the alloc tables and do some other stuff */
hdr_to_frps(&frame);//把从信息头中解压出来的信息加载
nch = frame.nch;
error_protection = header.error_protection;
//打开输出文件
FILE* result;
result = fopen("result.txt", "w+");
//while里面是获取的每一帧的信息
while (get_audio(musicin, buffer, num_samples, nch, &header) > 0) {
...
}
...
//关闭文件
fclose(result);
exit(0);
}
我们知道,在比特预算时,把计算所得的该帧总分配比特数赋给了adb,在adb获得值以后直接进行输出。
int main(int argc, char** argv)
{
...
adb = available_bits(&header, &glopts);//bit预算
lg_frame = adb / 8;
if (header.dab_extension) {
/* in 24 kHz we always have 4 bytes */
if (header.sampling_frequency == 1)
header.dab_extension = 4;
/* You must have one frame in memory if you are in DAB mode */
/* in conformity of the norme ETS 300 401 http://www.etsi.org */
/* see bitstream.c */
if (frameNum == 1)
minimum = lg_frame + MINIMUM;
adb -= header.dab_extension * 8 + header.dab_length * 8 + 16;
}
if (frameNum == 1)
{
//输出可用比特数
fprintf(result, "可用比特数:%d\n", adb);
}
...
}
通过调试,我们知道,实验中比例因子存放在scalar[][][]中,每个声道有SBLIMIT个子带,每个子带有3个比例因子。
值得注意的是,比例因子存放数组的定义为scalar[2][3][SBLIMIT],所以在写循环的时候需要格外注意顺序。
int main(int argc, char** argv)
{
...
scale_factor_calc(*sb_sample, scalar, nch, frame.sblimit);//计算比例因子
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);
scale_factor_calc(j_sample, &j_scale, 1, frame.sblimit);//计算比例因子选择信息
}
if (frameNum == 1)
{
//输出比例因子
fprintf(result, "\n比例因子:\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");
}
}
}
...
}
通过调试,我们知道,比特分配的结果存放在bit_alloc[][]中。每个声道有SBLIMIT个子带,每个子带有一个比特分配的结果。
int main(int argc, char** argv)
{
...
transmission_pattern(scalar, scfsi, &frame);
main_bit_allocation(smr, scfsi, bit_alloc, &adb, &frame, &glopts);//进行比特分配
if (frameNum == 1)
{
//输出比特分配结果
fprintf(result, "\n比特分配\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]);
}
}
}
...
}