数据压缩第八周作业——MPEG编码器

一、MPEG音频编码原理

思想原理:利用人耳的听觉特性,去除掉无法被人👂感知的音频部分。

基本框架:最重要的是理解这种图以及”带着镣铐跳舞“这句话的含义。
在这里插入图片描述

MPEG-2音频编码器架构:

  • 多项滤波器(32个子带):MPEG将输入的PCM音频码流变换为32个子带的频域信号,分解的思想其实就是子带编码思想(将原始信号分解为若干个子频带,对其分别进行编码,利用下采样能够降低传送数据的比特率,同时还能保持较小的失真范围。

  • 比例因子提取:输入的1152个样本=32x12x3,32是指分解成的32个子带,在经过一次分解后需要等12次,相当于1组由12个取样点组成,先找出12个样点中绝对值的最大值作为公共比例因子;接着等待三组,从三组中抽出最大的比例因子进行量化(减小运算量)

    (以上为时域部分要点)


    (下面是频域部分要点)

  • 心理声学模型:利用人耳的掩蔽特性,结合临界频带对输入的数据进行过滤,之保持频率最高的部分。

    • 输入FFT(频域信号)以及比例因子

    • 输出SMR(子带信号掩蔽比)

  • 动态比特分配:根据心理声学模型的计算结果,为每个自带信号分配比特数。

    • 输入比特预算和SMR
    • 输出每个自带对应的量化数

1、心理声学模型构建

主要思想: 人耳的听觉系统中存在一个听觉阈值电平,低于这个电平的声音信号就听不到。

  • 听觉阈值的大小随声音频率的改变而改变。
  • 一个人是否听到声音取决于声音的频率,以及声音的幅度是否高于这种频率下的听觉阈值
  • 人耳具有听觉掩蔽特性,人耳感知的听觉阈值电平是自适应的,会随听到的不同频率声音而发生变化

①听觉阈值:

  • 两个声音响度级相同,但强度不一定相同,还与频率有关(图中密密麻麻的线,属于等响度曲线,同一条线上的响度级相同。观察同一条曲线上的两点,其强度不一定相同)

  • 声压级越高,等响度曲线趋于平坦

在这里插入图片描述

②频域掩蔽

  • 听觉阈值电平是自适应的,会随听到的不同频率声音而发生变化
  • 如果有多个频率成分的复杂信号存在,那么频谱的总掩蔽阈值与频率的关系取决于各掩蔽音的强度、频率和它们之间的距离。
    在这里插入图片描述

临界频带
含义:当某个纯音被以它为中心频率、且具有一定带宽的连续噪声所掩蔽时,如果该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽称之为临界频带宽度

通常认为从20Hz到16kHz有25个临界频带,单位为bark,1 Bark = 一个临界频带的宽度:
在这里插入图片描述

④人耳听觉系统
主要思想:等效于一个信号通过一组并联的不同中心频率的带通滤波器。

  • 中心频率与信号频率相同的滤波器具有最大响应;中心频率偏离信号频率较多的滤波器不会产生响应。
  • 在0Hz到20KHz频率范围内由25个重叠的带通滤波器组成的滤波器组。
  • 听音者在噪声中听某一纯音信号时,只启用中心频率与信号频率相同的那个听觉滤波器,纯音信号通过该滤波器,而噪声信号只有通带范围内的部分信号能通过,通带以外的频率成分则被抑制,只有通过该滤波器的噪声才对掩蔽起作用。

在这里插入图片描述
⑤掩蔽音的关系

掩蔽音与被掩蔽音的组合方式有四种,即它们分别可以是乐音信号(弦信号,Tone)或窄带噪声(noise)。乐音信号和窄带噪声信号作为掩蔽音时产生的掩蔽效果有很大不同。

  • 噪声掩蔽纯音时,只有以纯音频率为中心的,一定频带宽度内的噪声能量起掩蔽作用,超出该频带的噪声能量无掩蔽效应,称掩蔽的临界带宽。掩蔽说明了频率选择性的极限
  • 掩蔽纯音信号,理论上使用带宽范围等于其临界带宽1/3倍频程的窄带噪声,这是因为掩蔽的临界带宽稍窄,听起来接近于纯音,患者常常混淆纯音与掩蔽噪声,而以纯音频率为中心频率的1/3倍频程噪声,宽度略大于临界带宽,同样可以起到很好的掩蔽效果。但实际应用中根据IEC645规定,临床听力计上常使用约4/10倍频程的窄带噪声

回顾声学模型:
在这里插入图片描述

上面一条线:通过子带分析滤波器组使信号具有高的时间分辨率,确保在短暂冲击信号情况下,编码的声音信号具有足够高的质量。
下面一条线:通过FFT运算具有高的频率分辨率。

上面一条线是音频编码的主线部分,下面一条线的本质是为了帮助计算线性量化器的量化比特数。其中,下面一条线最为出彩的部分是心理声学模型的应用,它对去除冗余信息起到了极大的作用。

时域-频域矛盾:举一个超级简单易懂的例子,不知道对不对,但是很好理解:

输入1152个样本,如果音频采样率是48kHz,对应的时间窗口就是24ms,观察一帧图像也就是按照24ms为单位。
在这里插入图片描述
反观频域:频率分辨率就是1/24,时间窗口越长(样本数越多),时域分辨率月底,而频域分辨率却越高。增大频域分辨力的同时时域分辨力必然会相应减小。

⑥动态比特分配

目的:使帧和每个子带的噪声-掩蔽比最小

在这里插入图片描述

  • 在调整到固定的码率之前,首先需要确定可用于样值编码的有效比特数,这个数值取决于比例因子、比例因子选择信息、比特分配信息以及辅助数据所需比特数。
  • 计算噪掩蔽的公式NMR=信掩比SMR-信噪比SNR(NMR表示波形误差和预测感知误差的关系,当NMR为负值时不需要考虑)
  • 首先假设SNR=0,按照比特预算的比特数,优先考虑NMR值最大的子带。
  • 每分配1bit就会降低6dB,依次循环~直到分配bit数=0或者所有子带的NMR都降低至0。

再次举一个超级简单的例子for example:
在这里插入图片描述

二、编码器设计分析

输入声音信号经过一个多相滤波器组,变换到多个子带,等待多组提取共同的比例因子,同时进行频率分析, 经过“心理声学模型” 计算以频率为自变量的噪声掩蔽阈值。量化和编码部分用信掩比SMR决定分配给子带信号的量化位数,使量化噪声小于掩蔽阈值。最后通过数据帧包装 将量化的子带样本和其它数据按照规定的帧格式组装成比特数据流。

在这里插入图片描述
首先我们查看命令行参数(命令行参数什么都不设置,输出,查看要求格式)
在这里插入图片描述
表示这里需要设置输入文件的名称以及输出文件的名称

下一步关注main函数:

int main(int argc, char** argv)
{
	/********************************参数初始化***************************************************/
	programName = argv[0];//argv[0]表示输入文件
	if (argc == 1)
		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);//输出配置信息

	hdr_to_frps(&frame);//加载信息头中解压出来的信息
	nch = frame.nch;
	error_protection = header.error_protection;

	//按帧获取信息
	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);//在码率分配前首先要计算码率预算,把计算所得的该帧总分配比特数赋给了adb,在adb获得值以后直接进行输出。
		lg_frame = adb / 8;
		if (header.dab_extension) {
			if (header.sampling_frequency == 1)
				header.dab_extension = 4;
			if (frameNum == 1)
				minimum = lg_frame + MINIMUM;
			adb -= header.dab_extension * 8 + header.dab_length * 8 + 16;
		}

		{
			int gr, bl, ch;
			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) {
			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)) {
			for (ch = 0; ch < nch; ch++) {
				for (sb = 0; sb < SBLIMIT; sb++)
					smr[ch][sb] = smrdef[ch][sb];
			}
		}
		else
		{
			//根据心理声学模型计算掩蔽电平
			switch (model) {
			case -1:
				psycho_n1(smr, nch);
				break;
			case 0://心理声学模型A计算掩蔽电平
				psycho_0(smr, nch, scalar, (FLOAT)s_freq[header.version][header.sampling_frequency] * 1000);//注意这里 输入比例因子,fft,输出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:
				psycho_3(buffer, max_sc, smr, &frame, &glopts);
				break;
			case 4:
				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:
				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:
				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);
				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);
}

着装关注几个非常重要的模块:比例因子提取、心理声学模型、动态比特分配

1、比例因子提取:

void scale_factor_calc (double sb_sample[][3][SCALE_BLOCK][SBLIMIT],
			unsigned int scalar[][3][SBLIMIT], int nch,
			int sblimit)
{
  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--;) {//12个一组寻找子带中的最大值
	int j;
	unsigned int l;
	register double temp;
	unsigned int scale_fac;
	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;
	}
	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;//得到比例因子
      }
    }
}

2、选取最大的比例因子

void pick_scale (unsigned int scalar[2][3][SBLIMIT], frame_info * frame,
		 double max_sc[2][SBLIMIT])
{
  int i, j, k, max;
  int nch = frame->nch;
  int sblimit = frame->sblimit;

  for (k = 0; k < nch; k++)
    for (i = 0; i < sblimit; max_sc[k][i] = multiple[max], i++)
      for (j = 1, max = scalar[k][0][i]; j < 3; j++)
	if (max > scalar[k][j][i])//循环找最大的比例因子
	  max = scalar[k][j][i];
  for (i = sblimit; i < SBLIMIT; i++)
    max_sc[0][i] = max_sc[1][i] = 1E-20;
}

3、心理声学模型(这里以我们使用的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];//较小的指标意味着较大的比例因子
	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 */
		}
		//在每个子带中找到最小的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++;
	}
	//找到这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];
	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];
}

4、动态码率分配

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)
{
	...
	//选择动态分配码率模式
	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 */在bitrateindextobits表中查找对此帧使用的比特率
			   
			for (brindex = lower; brindex <= upper; brindex++) {
				if (bitrateindextobits[brindex] > req) {
					guessindex = brindex;
					found = TRUE;
					break;
				}
			}
			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) {
			static int count = 0;
			int i;
			if ((count++ % 1000) == 0) {
				for (i = 1; i < 15; i++)
					fprintf(stdout, "%4i ", vbrstats[i]);
				fprintf(stdout, "\n");
			}
			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);
	}
}

5、输出音频的采样率和目标码率

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");
}

最终得到输出结果
在这里插入图片描述
输入文件名:test.wav 音频的采样率:44.1KHz
输出文件名:test.mp2 音频的目标码率为192Kbps

在main函数中加入代码输出比特分配结果

	if (frameNum == 1)
	{
		FILE* result;
		result = fopen("result.txt", "w");
		// 输出比例因子

		fprintf(result, "比例因子//\n");
		for (int k = 0; k < nch; k++)	// 每个声道单独输出
		{
			fprintf(result, "声道%d\n", k + 1);
			for (sb = 0; sb < frame.sblimit; sb++)	// 每个子带
			{
				fprintf(result, "子带[%d]:\t", sb + 1);
				for (int gr = 0; gr < 3; gr++) {
					fprintf(result, "%2d\t", scalar[k][gr][sb]);
				}
				fprintf(result, "\n");
			}
		}
		fprintf(result, "\n");

		//输出比特分配结果

		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);
	}

在这里插入图片描述
在这里插入图片描述

三、分析乐音、噪声、混合音三个音频文件

1、噪声
输入文件名:nosie.wav 音频的采样率:48KHz
输出文件名:nosie.mp2 音频的目标码率为192Kbps
在这里插入图片描述
2、test乐音
输入文件名:test.wav 音频的采样率:44.1KHz
输出文件名:test.mp2 音频的目标码率为192Kbps
在这里插入图片描述

3、mix混合音
输入文件名:mix.wav 音频的采样率:48KHz
输出文件名:mix.mp2 音频的目标码率为192Kbps
在这里插入图片描述

3、修改程序~输出比例因子、比特预算、比特分配结果

	if (frameNum == 1)//输出第一帧为例
	{
		FILE* result;
		result = fopen("result.txt", "w");
		// 输出比例因子
		fprintf(result, "比例因子//\n");
		for (int k = 0; k < nch; k++)	// 每个声道单独输出
		{
			fprintf(result, "声道%d\n", k + 1);
			for (sb = 0; sb < frame.sblimit; sb++)	// 每个子带
			{
				fprintf(result, "子带[%d]:\t", sb + 1);
				for (int gr = 0; gr < 3; gr++) {
					fprintf(result, "%2d\t", scalar[k][gr][sb]);
				}
				fprintf(result, "\n");
			}
		}
		fprintf(result, "\n");

		//输出比特分配结果

		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]);
			}
		}
		//输出比特预算
		fprintf(result, "比特预算//\n");
		fprintf(result, "%d bits\n", adb);
	}

4、查看result结果:

噪音乐音混合音
比例因子选择在这里插入图片描述在这里插入图片描述在这里插入图片描述
比特分配在这里插入图片描述在这里插入图片描述在这里插入图片描述
比特预算在这里插入图片描述在这里插入图片描述在这里插入图片描述

总结

  • MPEG的关键思想——掌握“时频两条线”(主线是时域线,最终的量化还是在时域线里进行,频域相当于只是利用生理特性限制条件)
  • 声学心理模型中,首先需要计算比特预算,将比特预算和频域共同输入声学模型,得到SMR(每个子带的信号-掩蔽比)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值