解码一帧Layer3第7步:IMDCT和子带混合 -- class Layer3内的hybrid方法
这一步可细分为3个步骤:
1.初始化加窗系数floatWinIMDCT[][] 初始化floatWinIMDCT[][]时直接代入相关公式,我这事先另外编程用公式把加窗系数计算出来,供程序中直接查表使用,而不是运行时进行初始化。初始化floatWinIMDCT[][]的代码正好还留着,就顺便贴出来:
public class InitIMDCT { public static void main(String args[]) { int i, j; final double PI12 = 0.26179938779914943653855361527329; final double PI36 = 0.087266462599716478846184538424431; final double PI72 = 0.043633231299858239423092269212215; double[][] doubleWinIMDCT = new double[4][36]; // type 0 for (i = 0; i < 36; i++) doubleWinIMDCT[0][i] = Math.sin(PI36 * (i + 0.5)); // type 1 for (i = 0; i < 18; i++) doubleWinIMDCT[1][i] = Math.sin(PI36 * (i + 0.5)); for (i = 18; i < 24; i++) doubleWinIMDCT[1][i] = 1.0; for (i = 24; i < 30; i++) doubleWinIMDCT[1][i] = Math.sin(PI12 * (i + 0.5 - 18)); for (i = 30; i < 36; i++) doubleWinIMDCT[1][i] = 0.0; // type 2 (not needed...) // type 3 for (i = 0; i < 6; i++) doubleWinIMDCT[3][i] = 0.0; for (i = 6; i < 12; i++) doubleWinIMDCT[3][i] = Math.sin(PI12 * (i + 0.5 - 6.0)); for (i = 12; i < 18; i++) doubleWinIMDCT[3][i] = 1.0; for (i = 18; i < 36; i++) doubleWinIMDCT[3][i] = Math.sin(PI36 * (i + 0.5)); for (i = 0; i < 4; i++) { doubleWinIMDCT[i][0] /= 2 * Math.cos(19 * PI72); doubleWinIMDCT[i][1] /= 2 * Math.cos(21 * PI72); doubleWinIMDCT[i][2] /= 2 * Math.cos(23 * PI72); doubleWinIMDCT[i][3] /= 2 * Math.cos(25 * PI72); doubleWinIMDCT[i][4] /= 2 * Math.cos(27 * PI72); doubleWinIMDCT[i][5] /= 2 * Math.cos(29 * PI72); doubleWinIMDCT[i][6] /= 2 * Math.cos(31 * PI72); doubleWinIMDCT[i][7] /= 2 * Math.cos(33 * PI72); doubleWinIMDCT[i][8] /= 2 * Math.cos(35 * PI72); doubleWinIMDCT[i][9] /= 2 * Math.cos(37 * PI72); doubleWinIMDCT[i][10] /= 2 * Math.cos(39 * PI72); doubleWinIMDCT[i][11] /= 2 * Math.cos(41 * PI72); doubleWinIMDCT[i][12] /= 2 * Math.cos(43 * PI72); doubleWinIMDCT[i][13] /= 2 * Math.cos(45 * PI72); doubleWinIMDCT[i][14] /= 2 * Math.cos(47 * PI72); doubleWinIMDCT[i][15] /= 2 * Math.cos(49 * PI72); doubleWinIMDCT[i][16] /= 2 * Math.cos(51 * PI72); doubleWinIMDCT[i][17] /= 2 * Math.cos(53 * PI72); doubleWinIMDCT[i][18] /= 2 * Math.cos(55 * PI72); doubleWinIMDCT[i][19] /= 2 * Math.cos(57 * PI72); doubleWinIMDCT[i][20] /= 2 * Math.cos(59 * PI72); doubleWinIMDCT[i][21] /= 2 * Math.cos(61 * PI72); doubleWinIMDCT[i][22] /= 2 * Math.cos(63 * PI72); doubleWinIMDCT[i][23] /= 2 * Math.cos(65 * PI72); doubleWinIMDCT[i][24] /= 2 * Math.cos(67 * PI72); doubleWinIMDCT[i][25] /= 2 * Math.cos(69 * PI72); doubleWinIMDCT[i][26] /= 2 * Math.cos(71 * PI72); doubleWinIMDCT[i][27] /= 2 * Math.cos(71 * PI72); doubleWinIMDCT[i][28] /= 2 * Math.cos(69 * PI72); doubleWinIMDCT[i][29] /= 2 * Math.cos(67 * PI72); doubleWinIMDCT[i][30] /= 2 * Math.cos(65 * PI72); doubleWinIMDCT[i][31] /= 2 * Math.cos(63 * PI72); doubleWinIMDCT[i][32] /= 2 * Math.cos(61 * PI72); doubleWinIMDCT[i][33] /= 2 * Math.cos(59 * PI72); doubleWinIMDCT[i][34] /= 2 * Math.cos(57 * PI72); doubleWinIMDCT[i][35] /= 2 * Math.cos(55 * PI72); } System.out.println("private static float[][] doubleWinIMDCT = {"); for(i = 0; i < 4; i++) { System.out.printf("{"); for(j = 0; j < 35; j++) { System.out.printf("%gf,", doubleWinIMDCT[i][j]); if(j % 6 == 5) System.out.printf("\n"); } System.out.printf("%gf},\n", doubleWinIMDCT[i][j]); } System.out.println("};"); } }
运行程序将输出COPY到源代码的“private static final float[][] floatWinIMDCT = ”那就行了。
2.IMDCT 这里用到两种反向改进型离散余弦变换(IMDCT):短块用12点的IMDCT;长块用36点IMDCT。在解码端应用IMDCT完成频域到时域的转换,IMDCT计算的公式是:
从公式可以看出,如果长块n=36,直接计算需要18*36=648次浮点乘法;如果是短块,则n=12,直接运算需要6*12=72次浮点乘法。解码一帧采用标准立体声编码的MP3需要调用4次,运算量很大,所以必须采用快速算法。程序中用到的快速算法的作者是Mikko Tommila(copyright 1997,现已应用于公共领域),后来由Jeff改进。出于改进程序运行速度的考虑,这里采用了快速算法的展开式。快速算法的推算时把公式展开为具有递推特性的表达式,利用递推式一直递推到2点和3点的IDCT。推导过程可以参考我以前的一篇贴子《MP3解码之DCT(32→64)快速算法的展开》,需要说明的是DCT与IDCT由于公式不同所以推算过程是完全不同的,但从这篇贴子可以看到利用“递推”特性逐步缩小乘法运算规模,就明白各点快速算法的函数了,即使明白了各点快速算法的函数,还是不建议你看展开式,看展开式是理不清头绪的,尽管源码中作了比较详细的说明。如果你想深入了解编解码知识的话,建议你亲自动手推导一下,我这里就省略掉IMDCT快速算法的推导过程,后文直接给快速算法的展开式。
3.混合滤波带(hybrid filterbank) 先定义一个先进先出的队列floatPrevBlck[][][],经IMDCT后产生的36个输出中的前18个值和这个队列中的18个值相加输出到xr[],再将IMDCT产生的36个输出值中的后18个写入队列;每解码完一个粒度组内的一个声道后要将当前的最大子带之后对应的队列数据清零。
【提示】以下代码是Layer3.java的一部分,应遵守《(一)用JAVA编写MP3解码器——前言》中的许可协议。
class Layer3内的hybrid方法的源码如下:
//7. //>>>>HYBRID(synthesize via iMDCT)========================================= private static final float[][] floatWinIMDCT = { {0.0322824f,0.1072064f,0.2014143f,0.3256164f,0.5f,0.7677747f, 1.2412229f,2.3319514f,7.7441506f,-8.4512568f,-3.0390580f,-1.9483297f, -1.4748814f,-1.2071068f,-1.0327232f,-0.9085211f,-0.8143131f,-0.7393892f, -0.6775254f,-0.6248445f,-0.5787917f,-0.5376016f,-0.5f,-0.4650284f, -0.4319343f,-0.4000996f,-0.3689899f,-0.3381170f,-0.3070072f,-0.2751725f, -0.2420785f,-0.2071068f,-0.1695052f,-0.1283151f,-0.0822624f,-0.0295815f}, {0.0322824f,0.1072064f,0.2014143f,0.3256164f,0.5f,0.7677747f, 1.2412229f,2.3319514f,7.7441506f,-8.4512568f,-3.0390580f,-1.9483297f, -1.4748814f,-1.2071068f,-1.0327232f,-0.9085211f,-0.8143131f,-0.7393892f, -0.6781709f,-0.6302362f,-0.5928445f,-0.5636910f,-0.5411961f,-0.5242646f, -0.5077583f,-0.4659258f,-0.3970546f,-0.3046707f,-0.1929928f,-0.0668476f, -0.0f,-0.0f,-0.0f,-0.0f,-0.0f,-0.0f}, {/* block_type = 2 */}, {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f, 0.3015303f,1.4659259f,6.9781060f,-9.0940447f,-3.5390582f,-2.2903500f, -1.6627548f,-1.3065630f,-1.0828403f,-0.9305795f,-0.8213398f,-0.7400936f, -0.6775254f,-0.6248445f,-0.5787917f,-0.5376016f,-0.5f,-0.4650284f, -0.4319343f,-0.4000996f,-0.3689899f,-0.3381170f,-0.3070072f,-0.2751725f, -0.2420785f,-0.2071068f,-0.1695052f,-0.1283151f,-0.0822624f,-0.0295815f} }; /* * inv_mdct -- 12点和36点IMDCT快速算法(展开式) */ private void inv_mdct(final float[] in, final float[] out, final int block_type) { int i, idx6 = 0; float in0,in1,in2,in3,in4,in5,in6,in7,in8,in9,in10,in11,in12,in13,in14,in15,in16,in17; float out0,out1,out2,out3,out4,out5,out6,out7,out8,out9, out10,out11,out12,out13,out14,out15,out16,out17, tmp; if(block_type == 2) { out[0]=out[1]=out[2]=out[3]=out[4]=out[5]=out[6]=out[7] =out[8]=out[9]=out[10]=out[11]=out[12]=out[13]=out[14] =out[15]=out[16]=out[17]=out[18]=out[19]=out[20]=out[21] =out[22]=out[23]=out[24]=out[25]=out[26]=out[27]=out[28] =out[29]=out[30]=out[31]=out[32]=out[33]=out[34]=out[35]=0.0f; for (i = 0; i < 3; i++) { //>>>>>>>>>>>> 12-point IMDCT //>>>>>> 6-point IDCT in[15 + i] += (in[12 + i] += in[9 + i]) + in[6 + i]; in[9 + i] += (in[6 + i] += in[3 + i]) + in[i]; in[3 + i] += in[i]; //>>> 3-point IDCT on even out1 = (in1 = in[i]) - (in2 = in[12+i]); in3 = in1 + in2 * 0.5f; in4 = in[6+i] * 0.8660254f; out0 = in3 + in4; out2 = in3 - in4; //<<< End 3-point IDCT on even //>>> 3-point IDCT on odd (for 6-point IDCT) out4 = ((in1 = in[3+i]) - (in2 = in[15+i])) * 0.7071068f; in3 = in1 + in2 * 0.5f; in4 = in[9+i] * 0.8660254f; out5 = (in3 + in4) * 0.5176381f; out3 = (in3 - in4) * 1.9318516f; //<<< End 3-point IDCT on odd // Output: butterflies on 2,3-point IDCT's (for 6-point IDCT) tmp = out0; out0 += out5; out5 = tmp - out5; tmp = out1; out1 += out4; out4 = tmp - out4; tmp = out2; out2 += out3; out3 = tmp - out3; //<<<<<< End 6-point IDCT //<<<<<<<<<<<< End 12-point IDCT // Shift in1 = out3 * 0.1072064f; out[6 + idx6] += in1; out[7 + idx6] += out4 * 0.5f; out[8 + idx6] += out5 * 2.3319512f; out[9 + idx6] -= out5 * 3.0390580f; out[10 + idx6] -= out4 * 1.2071068f; out[11 + idx6] -= in1 * 7.5957541f; out[12 + idx6] -= out2 * 0.6248445f; out[13 + idx6] -= out1 * 0.5f; out[14 + idx6] -= out0 * 0.4000996f; out[15 + idx6] -= out0 * 0.3070072f; out[16 + idx6] -= out1 * 0.2071068f; out[17 + idx6] -= out2 * 0.0822623f; idx6 += 6; } } else { //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 36-point IDCT //>>>>>>>>>>>>>>>>>> 18-point IDCT for odd in[17] += (in[16] += in[15]) + in[14]; in[15] += (in[14] += in[13]) + in[12]; in[13] += (in[12] += in[11]) + in[10]; in[11] += (in[10] += in[9]) + in[8]; in[9] += (in[8] += in[7]) + in[6]; in[7] += (in[6] += in[5]) + in[4]; in[5] += (in[4] += in[3]) + in[2]; in[3] += (in[2] += in[1]) + in[0]; in[1] += in[0]; //>>>>>>>>> 9-point IDCT on even /* * for(i = 0; i < 9; i++) { * sum = 0; * for(j = 0; j < 18; j += 2) * sum += in[j] * cos(PI36 * (2 * i + 1) * j); * out18[i] = sum; * } */ in0 = in[0] + in[12] * 0.5f; in1 = in[0] - in[12]; in2 = in[8] + in[16] - in[4]; out4 = in1 + in2; in3 = in1 - in2 * 0.5f; in4 = (in[10] + in[14] - in[2]) * 0.8660254f; // cos(PI/6) out1 = in3 - in4; out7 = in3 + in4; in5 = (in[4] + in[8]) * 0.9396926f; //cos( PI/9) in6 = (in[16] - in[8]) * 0.1736482f; //cos(4PI/9) in7 = -(in[4] + in[16]) * 0.7660444f; //cos(2PI/9) in17 = in0 - in5 - in7; in8 = in5 + in0 + in6; in9 = in0 + in7 - in6; in12 = in[6] * 0.8660254f; //cos(PI/6) in10 = (in[2] + in[10]) * 0.9848078f; //cos(PI/18) in11 = (in[14] - in[10]) * 0.3420201f; //cos(7PI/18) in13 = in10 + in11 + in12; out0 = in8 + in13; out8 = in8 - in13; in14 = -(in[2] + in[14]) * 0.6427876f; //cos(5PI/18) in15 = in10 + in14 - in12; in16 = in11 - in14 - in12; out3 = in9 + in15; out5 = in9 - in15; out2 = in17 + in16; out6 = in17 - in16; //<<<<<<<<< End 9-point IDCT on even //>>>>>>>>> 9-point IDCT on odd /* * for(i = 0; i < 9; i++) { * sum = 0; * for(j = 0;j < 18; j += 2) * sum += in[j + 1] * cos(PI36 * (2 * i + 1) * j); * out18[17-i] = sum; * } */ in0 = in[1] + in[13] * 0.5f; //cos(PI/3) in1 = in[1] - in[13]; in2 = in[9] + in[17] - in[5]; out13 = (in1 + in2) * 0.7071068f; //cos(PI/4) in3 = in1 - in2 * 0.5f; in4 = (in[11] + in[15] - in[3]) * 0.8660254f; //cos(PI/6) out16 = (in3 - in4) * 0.5176381f; // 0.5/cos( PI/12) out10 = (in3 + in4) * 1.9318517f; // 0.5/cos(5PI/12) in5 = (in[5] + in[9]) * 0.9396926f; // cos( PI/9) in6 = (in[17] - in[9])* 0.1736482f; // cos(4PI/9) in7 = -(in[5] + in[17])*0.7660444f; // cos(2PI/9) in17 = in0 - in5 - in7; in8 = in5 + in0 + in6; in9 = in0 + in7 - in6; in12 = in[7] * 0.8660254f; // cos(PI/6) in10 = (in[3] + in[11]) * 0.9848078f; // cos(PI/18) in11 = (in[15] - in[11])* 0.3420201f; // cos(7PI/18) in13 = in10 + in11 + in12; out17 = (in8 + in13) * 0.5019099f; // 0.5/cos(PI/36) out9 = (in8 - in13) * 5.7368566f; // 0.5/cos(17PI/36) in14 = -(in[3] + in[15]) * 0.6427876f; // cos(5PI/18) in15 = in10 + in14 - in12; in16 = in11 - in14 - in12; out14 = (in9 + in15) * 0.6103873f; // 0.5/cos(7PI/36) out12 = (in9 - in15) * 0.8717234f; // 0.5/cos(11PI/36) out15 = (in17 + in16) * 0.5516890f; // 0.5/cos(5PI/36) out11 = (in17 - in16) * 1.1831008f; // 0.5/cos(13PI/36) //<<<<<<<<< End 9-point IDCT on odd // Butterflies on 9-point IDCT's tmp = out0; out0 += out17; out17 = tmp - out17; tmp = out1; out1 += out16; out16 = tmp - out16; tmp = out2; out2 += out15; out15 = tmp - out15; tmp = out3; out3 += out14; out14 = tmp - out14; tmp = out4; out4 += out13; out13 = tmp - out13; tmp = out5; out5 += out12; out12 = tmp - out12; tmp = out6; out6 += out11; out11 = tmp - out11; tmp = out7; out7 += out10; out10 = tmp - out10; tmp = out8; out8 += out9; out9 = tmp - out9; //<<<<<<<<<<<<<<<<<< End 18-point IDCT //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< End 36-point IDCT // Shift final float[] winp = floatWinIMDCT[block_type]; out[0] = out9 * winp[0]; out[1] = out10 * winp[1]; out[2] = out11 * winp[2]; out[3] = out12 * winp[3]; out[4] = out13 * winp[4]; out[5] = out14 * winp[5]; out[6] = out15 * winp[6]; out[7] = out16 * winp[7]; out[8] = out17 * winp[8]; out[9] = out17 * winp[9]; out[10] = out16 * winp[10]; out[11] = out15 * winp[11]; out[12] = out14 * winp[12]; out[13] = out13 * winp[13]; out[14] = out12 * winp[14]; out[15] = out11 * winp[15]; out[16] = out10 * winp[16]; out[17] = out9 * winp[17]; out[18] = out8 * winp[18]; out[19] = out7 * winp[19]; out[20] = out6 * winp[20]; out[21] = out5 * winp[21]; out[22] = out4 * winp[22]; out[23] = out3 * winp[23]; out[24] = out2 * winp[24]; out[25] = out1 * winp[25]; out[26] = out0 * winp[26]; out[27] = out0 * winp[27]; out[28] = out1 * winp[28]; out[29] = out2 * winp[29]; out[30] = out3 * winp[30]; out[31] = out4 * winp[31]; out[32] = out5 * winp[32]; out[33] = out6 * winp[33]; out[34] = out7 * winp[34]; out[35] = out8 * winp[35]; } } private static float[] floatRawOut; // [36]; private static float[][][] floatPrevBlck; // [2][32][18]; private void hybrid(final int ch, final int gr) { GRInfo gr_info = (objSI.ch[ch].gr[gr]); int sb, ss, bt; int max_sb = (17 + rzero_index[ch]) / 18; for (sb = 0; sb < max_sb; sb++) { bt = ((gr_info.window_switching_flag != 0) && (gr_info.mixed_block_flag != 0) && (sb < 2)) ? 0 : gr_info.block_type; inv_mdct(xr[ch][sb], floatRawOut, bt); for(ss = 0; ss < 18; ss++) { xr[ch][sb][ss] = floatRawOut[ss] + floatPrevBlck[ch][sb][ss]; floatPrevBlck[ch][sb][ss] = floatRawOut[18 + ss]; } } for (; sb < 32; sb++) for(ss = 0; ss < 18; ss++) { xr[ch][sb][ss] = floatPrevBlck[ch][sb][ss]; floatPrevBlck[ch][sb][ss] = 0; } } //<<<<HYBRID(synthesize via iMDCT)=========================================
相关推荐
### MP3解码算法原理详解 #### 一、概述 MP3作为一种广泛使用的音频压缩格式,其高效的数据压缩技术使其成为数字音乐领域的标准之一。本文将深入探讨MP3解码的具体算法及其工作原理,帮助读者更好地理解MP3格式的...
在MP3编解码算法中,IMDCT(Inverse Modified Discrete Cosine Transform)是一个计算密集且被频繁调用的操作,因此非常适合通过硬件实现,以减轻中央处理器的负担和降低功耗,从而提高整个系统的性能。 本研究首先...
本文主要探讨了如何使用DSP Builder实现MP3音频解码过程中的逆离散余弦变换(Inverse Modified Discrete Cosine Transform,IMDCT)。MDCT(Modified Discrete Cosine Transform)与IMDCT是两种重要的重叠正交变换,在...
提出了一种输入序列长度为N=5×2m的改进型的离散余弦变换(MDCT)的有效算法,可以有效减少数据量,提高计算机储存和运算效率.首先将序列长度为N的MDCT转化为N/2的离散余弦变换IV型(DCT-IV) ,然后将后者转化为...
为了提高计算效率,逆离散余弦变换(IMDCT)通常会采用快速算法进行加速。本文将详细介绍一种基于快速傅里叶变换(FFT)的IMDCT算法,该方法来源于Marina Bosi的著作《Introduction to Digital Audio Coding and ...
利用FPGA实现MP3音频解码器的原型芯片设计,可以让设计者在硬件层面优化解码算法的性能,同时能够根据需要快速调整电路设计。 设计与实现过程中涉及的关键知识点包括: 1. 数字信号处理(DSP):在FPGA中实现MP3...
综上所述,基于DCT-4的IMDCT算法是一种非常高效且实用的技术,在音频编码和解码等应用场景中有着重要的作用。特别是对于FFmpeg这样的多媒体框架而言,这种算法的引入能够显著提升其处理性能。通过对IMDCT到DCT-4再到...
本文通过使用C语言实现DRA解码器,并使用二叉树搜索法进行Huffman解码,使用FFT实现IMDCT变换来优化DRA解码算法。基于这两种优化算法,本文提出了DRA音频解码的具体实现方案。 三、Android平台上优化DRA音频解码器 ...
综上所述,《MP3音频解码器的FPGA原型芯片设计与实现》这篇论文通过对MP3解码器的设计和实现进行了深入探讨,提出了有效的算法融合技术和流水线设计策略,成功地在FPGA平台上实现了高性能的MP3解码器。这一成果不仅...
与已有的一些IMDCT快速算法相比,新的分解算法计算效率提高了3倍;硬件实现减少了1个锁存器(20%)、4个加法器(44%)和3个乘法器(50%)。设计相应的IMDCT 硬件加速器并应用于AC-3音频的实时解码,验证了该算法的实用性。
### MP3解码算法原理详解 #### 一、引言 MP3作为一种广泛使用的音频压缩格式,其解码过程对于理解和应用音频技术至关重要。本文旨在详细介绍MP3解码算法的基本原理,帮助读者深入理解MP3音频文件是如何被解码并...
- **算法优化**:采用更高效的算法,如快速DCT算法,降低计算复杂度。 - **多线程与多核**:在多核ARM处理器上,可将解码过程分解为多个任务,分配到不同核心执行。 - **预读取和后写入**:预测未来需要的数据,...
开发者可以研究这些源代码,了解如何在实际项目中集成和使用imdct算法,以实现AAC音频的解码功能。 理解并掌握AAC音频编码中的imdct模块对于音频处理、嵌入式系统开发、流媒体服务以及移动设备应用开发等领域都具有...
通过使用C5509 DSP处理器,实现了高效的MP3解码运算,满足了44.1kHz采样率的MP3数据流的解码需求。 一个重要的技术点是霍夫曼解码,霍夫曼树是数据压缩中的一种算法,用于对数据进行压缩和解压缩。在MP3解码中,...
为了减少运算量并节省存储空间,研究人员采用了基于Lee DCT的改进型快速算法,这使得运算量减少了约三分之二。 2. **霍夫曼解码**:通过采用树型搜索的快速算法,提高了解码效率。 3. **逆量化模块**:通过对...
MDCT,全称为Modified Discrete Cosine Transform(改良的离散余弦变换),是一种在音频编码,特别是MP3编解码中广泛应用的信号处理技术。它在数字信号处理领域具有重要地位,因为其能有效地对时域信号进行频域分析...
文章主要讨论如何使用DSP Builder来实现MP3音频解码中的IMDCT。MDCT和IMDCT是2种重叠正交变换,也是MPEG音频标准中运算量最大的2种运算,主要应用在数字信号处理当中。采用正弦递归循环公式,实现IMDCT的内核,得到...
MP3解码原理是数字音频编码技术的一种,其标准遵循ISO/IEC 11172-3(MPEG 1 ...整个解码过程中,madlib解码库被用作实现这些复杂步骤的工具集,它提供了高效且准确的解码算法,确保MP3音频文件能被正确地还原并播放。