`
lfp001
  • 浏览: 100702 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(十一)用JAVA编写MP3解码器——立体声处理

阅读更多

解码一帧Layer3第5步:立体声处理 -- class Layer3的ms_stereo和i_stereo方法

 

      MP3采用的立体声编码方式有中侧立体和强度立体声两种。

      1.中侧立体声(Middle/Side stereo)简称MS_stereo,在这种模式中,用中/侧声道规格化值Mi/Si取代左/右声道的值Li/Ri,重建左/右声道的值Li/Ri用下述公式:

      变换前Mi值在左声道,Si值在右声道。应用上述公式把Mi/Si频谱值变换为Li/Ri并放到左/右声道,就完成了中侧立体声解码。

 

      2.强度立体声(intensity stereo)  在MP3编码一帧结束后,有损压缩把频谱中表现音乐细节的高频成份压缩掉了。为了保留频谱中的高频部分,把这些高频数据编码附加到频带的后面部分。以长块为例,用rzero_bandL保存非零哈夫曼值的频带数,则从rzero_bandL至21的频带为强度立体声的编码数据。

      压制MP3时采用强度立体声编码,能提升音乐的细节,使压缩后的MP3听起来层次上更丰富。但是,很遗憾地告诉你,强度立体声是专利算法,受法律保护滴,很多MP3压缩器都没的这个功能,所以用强度立体声编码的MP3并不多见。

      对采用强度立体声编码的MP3,是否其进行强度声解码,不是训练有素的耳朵,听不出差别,反正我在调试程序时硬就没听出关闭强度立体声解码前后的区别。ISO/IEC 11172-3不对混合块中的长块作强度立体声处理,但很多MP3解码程序都作了处理,源码中把处理混合块中的长块的强度立体声的代码注释掉了,如果你愿意的话,可以取消掉注释把它加进来。是否对混合块中的长块作强度立体声处理,我也听不出什么差别,音乐细胞不发达呀,尽管我很喜欢听。记得去年的某个时候,我把以前买的CD拿出来听,好久没听过了,特亲切。放CD没的MP3方便,于是上网一顿海搜,找到MP3压缩器的No.1--LAME,用VBR模式的128Kpbs--320Kpbs,540M的CD压缩至不到60M,听起来和CD没的什么差别,觉得MP3编码真是个好,于是又上网海搜,想了解下MP3的技术细节,但是很遗憾,其中泛泛而谈的多,深入介绍其细节的少。好奇心的驱使下,想搞明白MP3的那些事,很长一段时间,业余时间就耗这上面了。也是有感于很多涉及MP3解码的关键技术的论文,都不是免费的,我就想把我弄清的部分公开出来,算是一个科谱宣传吧(这话说的:)可能你比我还懂的多)。

 

      联合立体声,请复习《(二)用JAVA编写MP3解码器——帧头信息解码》,对联合立体声(jiont stereo)作了简介。

 

【提示】以下代码是Layer3.java的一部分,应遵守《(一)用JAVA编写MP3解码器——前言》中的许可协议。

 

      今天就说到这,下回再说,上源码。class Layer3内的立体声解码方法的源码如下:

	//5.
	//>>>>STEREO===============================================================
	/*
	 * 在requantizer方法内已经作了除以根2处理, ms_stereo()内不再除以根2.
	 */
	private void ms_stereo() {
		int sb, ss;
		float tmp0, tmp1;
		int rzero_xr = (rzero_index[0] > rzero_index[1]) ? rzero_index[0] : rzero_index[1];
		int rzero_sb = (rzero_xr + 17) / 18;
		for (sb = 0; sb < rzero_sb; sb++)
			for (ss = 0; ss < 18; ss++) {
				tmp0 = xr[0][sb][ss];
				tmp1 = xr[1][sb][ss];
				xr[0][sb][ss] = tmp0 + tmp1;
				xr[1][sb][ss] = tmp0 - tmp1;
			}
		rzero_index[0] = rzero_index[1] = rzero_xr;
	}

	private static float[][] lsf_is_coef;
	private static float[] is_coef;
	/*
	 *  解码一个频带强度立体声,MPEG 1.0
	 */
	private void is_lines_1(int is_pos, int idx0, int max_width,int idx_step) {
		float xr0;
		int sb32 = idx0 / 18;
		int ss18 = idx0 % 18;
		for (int w = max_width; w > 0; w--) {
			xr0 = xr[0][sb32][ss18];
			xr[0][sb32][ss18] = xr0 * is_coef[is_pos];
			xr[1][sb32][ss18] = xr0 * is_coef[6 - is_pos];
			ss18 += idx_step;
			if (ss18 >= 18) {
				ss18 -= 18;
				sb32++;
			}
		}
	}
	/*
	 * 解码一个频带强度立体声,MPEG 2.0/2.5
	 */
	private void is_lines_2(int tab2, int is_pos, int idx0, int max_width,int idx_step) {
		float xr0;
		int sb32 = idx0 / 18;
		int ss18 = idx0 % 18;
		for (int w = max_width; w > 0; w--) {
			xr0 = xr[0][sb32][ss18];
			if (is_pos == 0)
				xr[1][sb32][ss18] = xr0;
			else {
				if ((is_pos & 1) == 0)
					xr[1][sb32][ss18] = xr0 * lsf_is_coef[tab2][(is_pos - 1) >> 1];
				else {
					xr[0][sb32][ss18] = xr0 * lsf_is_coef[tab2][(is_pos - 1) >> 1];
					xr[1][sb32][ss18] = xr0;
				}
			}
			ss18 += idx_step;
			if (ss18 >= 18) {
				ss18 -= 18;
				sb32++;
			}
		}
	}

	/*
	 * 强度立体声(intensity stereo)解码
	 * 公式:
	 * lsf_is_coef -- coefficients for LSF intensity stereo,ISO 13818-3,sesion 2.4.3.2
	 * lsf_is_coef[0][i] = (1 / sqrt(sqrt(2)))^(i + 1)
	 * lsf_is_coef[1][i] = (1 /      sqrt(2)) ^(i + 1)
	 * i=0..14
	 *
	 * is_coef -- coefficients for intensity stereo,iso11172-3,sesion 2.4.3.4.9.3
	 * is_coef[i] = tan(i * (PI / 12))
	 * is_coef[i] = is_coef[i] / (1 + is_coef[i])
	 * i=0..6
	 */
	private void i_stereo(final int gr) {
		if(objSI.ch[0].gr[gr].mixed_block_flag != objSI.ch[1].gr[gr].mixed_block_flag
				|| objSI.ch[0].gr[gr].block_type != objSI.ch[1].gr[gr].block_type)
			return;
		GRInfo gr_info = objSI.ch[1].gr[gr];	//信息保存在右声道.
		int is_p, idx, sfb;

		if(objHeader.getVersion() == Header.MPEG1) {	//MPEG 1.0
			if(gr_info.block_type == 2) {
				//MPEG 1.0, short block/mixed block
				int w3;
				//int do_long = 0;
				//if(gr_info.mixed_block_flag == 1)
				//	do_long = 1;
				for (w3 = 0; w3 < 3; w3++) {
					sfb = rzero_bandS[w3]; //混合块sfb最小为3
					//if (sfb > 3)
					//	do_long = 0;
					for (; sfb < 12; sfb++) {
						idx = 3*intSfbIdxShort[sfb] + w3;
						is_p = scfS[1][w3][sfb];
						if(is_p >= 7)
							continue;
						is_lines_1(is_p,idx,intWidthShort[sfb],3);
					}
				}
				/*if(do_long == 1) {
					for (sfb = rzero_bandL; sfb < 8; sfb++) {
						is_p = scfL[1][sfb];
						if(is_p < 7)
							is_lines_1(is_p,sfbIndexOfEndL[sfb],intWidthLong[sfb],1);
					}
				}*/
			} else {
				//MPEG 1.0, long block
				for (sfb = rzero_bandL; sfb <= 21; sfb++) {
					is_p = scfL[1][sfb];
					if(is_p < 7)
						is_lines_1(is_p,intSfbIdxLong[sfb],intWidthLong[sfb],1);
				}
			}
		} else {	//MPEG 2.0/2.5
			final int tab2 = gr_info.scalefac_compress & 0x1;
			if(gr_info.block_type == 2) {
				//MPEG 2.0/2.5, short block/mixed block
				int w3;
				//int do_long = 0;
				for (w3 = 0; w3 < 3; w3++) {
					sfb = rzero_bandS[w3]; //混合块sfb最小为3
					//if (sfb > 3)
					//	do_long = 0;
					for (; sfb < 12; sfb++) {
						idx = 3*intSfbIdxShort[sfb] + w3;
						is_p = scfS[1][w3][sfb];
						is_lines_2(tab2, scfS[1][w3][sfb], idx, intWidthShort[sfb],3);
					}
				}
				//if(do_long == 1)
				//	for (sfb = rzero_bandL; sfb < 8; sfb++)
				//		is_lines_2(tab2, scfL[1][sfb], sfbIndexOfEndL[sfb], intWidthLong[sfb],1);
			} else {
				//MPEG 2.0/2.5, long block
				for (sfb = rzero_bandL; sfb <= 21; sfb++)
					is_lines_2(tab2, scfL[1][sfb], intSfbIdxLong[sfb], intWidthLong[sfb],1);
			}
		}
	}
	//<<<<STEREO===============================================================

 

上一篇:(十)用JAVA编写MP3解码器——逆量化和重排序

下一篇:(十二)用JAVA编写MP3解码器——消混叠处理

 

【下载地址】http://jmp123.sourceforge.net/

 

  • 大小: 3 KB
分享到:
评论
6 楼 lfp001 2010-08-28  
sunjun 写道
一看就知道应该是写c/c++的朋友

是因为变量命名不合JAVA规范吗?
约定俗成,变量名采用官方文档中的名称描述,这样做是为了想借助相关文档深入了解MP3解码的朋友更方便一点吧。
5 楼 sunjun 2010-08-27  
一看就知道应该是写c/c++的朋友
4 楼 lfp001 2010-08-26  
是的。
完成解码一帧Layer3十多个步骤就可以解码Layer3了,再加上音频播放模块就可以播放了。
3 楼 mark.chinama 2010-08-26  
大师,能不能把流程串起来,比如


1  读取文件(......代码)
2  对文件的字符进行编码(.....代码)
...........最后就可以播放mp3了。


我能看懂你写的每一步要做的事情,不明白为什么要做
2 楼 mengzhaopeng 2010-08-25  
看不大董,冒似比较麻烦
1 楼 zhengbiao5 2010-08-25  
虽然不怎么懂~但是很佩服lz的精神!
收藏待用。

相关推荐

    java编写的解码器

    5. **重采样和声道处理**:如果MP3是立体声,解码器需要处理左右声道的关系,例如立体声联合立体声或单声道混合。此外,根据原始采样率和目标采样率,可能需要进行重采样。 6. **音频数据输出**:最后,解码器将...

    java的mp3解码器(非JMF、控制台播放音乐)

    标签"java mp3 无JMF 解码器"进一步强调了这个解码器的关键特性:它是用Java语言编写的,专注于MP3格式,且不依赖JMF。这使得它具有跨平台性,可以在任何支持Java的系统上运行。 压缩包内的文件"jmp123_400_utf8_...

    java mp3 音频文件解码器

    总结来说,Java MP3音频文件解码器是一个独立的、用纯Java编写的工具,用于将MP3文件转换为可处理的原始音频数据。它的设计和实现涉及了音频编码原理、数据处理优化以及Java编程技术,对于理解和处理音频数据的...

    纯JAVA的MP3解码器jmp

    《纯JAVA的MP3解码器jmp:深入解析与应用》 MP3解码器是数字音频处理领域的重要工具,它能够将存储的MP3格式音频数据转化为人类可听的声音信号。在众多的MP3解码器中,“jmp123”以其独特的纯JAVA实现和出色的性能...

    基于通用可编程GPU的视频编解码器——架构、算法与实现

    基于通用可编程GPU的视频编解码器——架构、算法与实现

    C++实现的Mp3解码器

    这些头文件对于使用解码器的开发者来说至关重要,因为它们提供了与解码器交互的API,包括打开MP3文件、初始化解码器、解码音频帧和获取解码后的声音数据等功能。 最后,`Makefile`是构建系统的配置文件,它定义了...

    java编写的mp3播放器

    读取MP3文件需要使用Java的I/O流,如FileInputStream和BufferedInputStream,来高效地读取和处理文件内容。 8. **用户界面设计**: 使用JavaFX或Swing库可以创建包含播放/暂停按钮、音量控制器、播放列表等元素的...

    mp3解码算法原理——具体解码算法

    MP3解码的过程涉及多个模块协同工作,主要包括同步及差错检查、主控模块、尺度因子解码、哈夫曼解码、逆量化、立体声解码、混淆缩减、IMDCT、频率反转以及合成多相滤波等关键步骤。 1. **同步及差错检查**:该模块...

    mp3解码器论文和Java源码

    论文可能会介绍如何使用Java来实现解码算法,包括使用Java的IO流处理位流,以及如何利用Java的多线程和内存管理优化性能。 5. **源码分析**:源码是理解理论知识的最佳实践。通过阅读和分析代码,开发者可以了解到...

    java编写mp3播放器.doc

    《使用Java编写MP3播放器》是一份关于利用Java编程语言实现MP3音频解码的文档。MP3作为广泛使用的音频压缩格式,其解码技术是数字音频处理领域的重要组成部分。该文档旨在介绍如何利用Java编写一个MP3解码器,并提供...

    立体声编解码方法、编解码器及编解码系统.pdf

    总结来说,该发明提供了一种创新的立体声处理技术,通过对采样率的智能判断和声道信息的精巧处理,实现了高效的编码和高质量的解码。这对于多媒体产业,特别是在音频压缩、传输和播放等方面具有重要的实用价值。通过...

    mina自定义编解码器详解

    - 文件`example`可能包含了一个使用mina编写的服务器或客户端程序,其中包含了自定义编解码器的应用实例。 - `MinaCodec`可能是一个包含编码器和解码器的类,我们来详细分析其工作流程: - 在编码器中,通常有一...

    MP3播放器——JAVA实现

    在本文中,我们将深入探讨如何使用Java编程语言来实现一个MP3播放器。MP3播放器是音频处理软件,能够读取、解码并播放MP3格式的音频文件。Java以其跨平台的特性,成为开发此类应用的理想选择。让我们一起探讨实现这...

    jmf_mp3解码器

    总的来说,"jmf_mp3解码器"结合JLayer1.0.1的使用,为Java开发者提供了一个跨平台的解决方案,使得在Java应用程序中播放MP3文件变得简单而有效。这种技术的应用场景广泛,可以用于开发音乐播放器、多媒体教学软件、...

    H.264编解码器——jm最新版14.2

    在描述中提到的VC下的C工程源码,意味着这个编解码器是用C语言编写,并且可以在Visual C++环境下编译和运行。这对于软件开发者来说非常有用,因为C语言的源代码通常更容易理解和修改,便于进行二次开发和定制。 ...

    JAVA编写的MP3播放器(有代码的哦)

    Java编写的MP3播放器是一种基于Java编程语言开发的音频播放软件,主要用于播放MP3格式的音频文件。这种播放器的实现主要依赖于Java的多媒体处理库,如Java Media Framework (JMF) 或者 jogl 等第三方库。下面我们将...

    优化过的MP3解码程序.tar.gz_MP3编解码_MP3解码_mp3 decoder_mp3 解码_mp3解码程序

    5. **立体声处理**:MP3支持多种立体声编码技术,如立体声联合编码(JS)和强度立体声编码(IS)。解码器需要正确处理这些模式,以还原出正确的立体声效果。 6. **比特流处理**:优化过的解码器可能会对比特流进行...

    java对于MP3的spi

    例如,以下是一个简单的示例代码片段,演示了如何使用Java Sound API和MP3 SPI播放MP3文件: ```java import javax.sound.sampled.*; public class MP3Player { public static void main(String[] args) { try {...

    非常简练的mp3解码器的代码

    5. **立体声处理**:对于立体声MP3,解码器还需要处理诸如立体声联合、强度立体声和中间/侧边编码等技术,以还原双声道音频。 6. **比特流增强**:一些MP3文件可能包含额外的比特流信息,如VBR(可变比特率)头部,...

Global site tag (gtag.js) - Google Analytics