/* This file is part of jpcsp. Jpcsp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jpcsp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.media.codec.mp3; import static java.lang.Math.pow; import static jpcsp.media.codec.mp3.Mp3Data.MODE_EXT_I_STEREO; import static jpcsp.media.codec.mp3.Mp3Data.MODE_EXT_MS_STEREO; import static jpcsp.media.codec.mp3.Mp3Data.band_size_long; import static jpcsp.media.codec.mp3.Mp3Data.band_size_short; import static jpcsp.media.codec.mp3.Mp3Data.ci_table; import static jpcsp.media.codec.mp3.Mp3Data.exp_table; import static jpcsp.media.codec.mp3.Mp3Data.expval_table; import static jpcsp.media.codec.mp3.Mp3Data.lsf_nsf_table; import static jpcsp.media.codec.mp3.Mp3Data.mp3_bitrate_tab; import static jpcsp.media.codec.mp3.Mp3Data.mp3_freq_tab; import static jpcsp.media.codec.mp3.Mp3Data.mp3_quant_bits; import static jpcsp.media.codec.mp3.Mp3Data.mpa_huff_data; import static jpcsp.media.codec.mp3.Mp3Data.mpa_pretab; import static jpcsp.media.codec.mp3.Mp3Data.mpa_quad_bits; import static jpcsp.media.codec.mp3.Mp3Data.mpa_quad_codes; import static jpcsp.media.codec.mp3.Mp3Data.slen_table; import static jpcsp.media.codec.mp3.Mp3Dsp.mdct_win; import java.util.Arrays; import org.apache.log4j.Logger; import jpcsp.media.codec.ICodec; import jpcsp.media.codec.mp3.Mp3Data.HuffTable; import jpcsp.media.codec.util.BitBuffer; import jpcsp.media.codec.util.BitReader; import jpcsp.media.codec.util.CodecUtils; import jpcsp.media.codec.util.FloatDSP; import jpcsp.media.codec.util.VLC; public class Mp3Decoder implements ICodec { public static Logger log = Logger.getLogger("mp3"); public static final int MP3_ERROR = -3; private static final int HEADER_SIZE = 4; public static final int BACKSTEP_SIZE = 512; public static final int EXTRABYTES = 24; public static final int LAST_BUF_SIZE = 2 * BACKSTEP_SIZE + EXTRABYTES; public static final int MP3_MAX_CHANNELS = 2; public static final int SBLIMIT = 32; // number of subbands public static final int MP3_STEREO = 0; public static final int MP3_JSTEREO = 1; public static final int MP3_DUAL = 2; public static final int MP3_MONO = 3; public static final int FRAC_BITS = 23; // fractional bits for sbSample snad dct public static final int WFRAC_BITS = 16; // fractional bits for window public static final int FRAC_ONE = 1 << FRAC_BITS; public static final float IMDCT_SCALAR = 1.759f; private Context ctx; private BitReader br; private BitBuffer bb = new BitBuffer(4096 * 8); private static boolean initializedTables = false; // vlc structure for decoding layer 3 Huffman tables private static VLC huff_vlc[] = new VLC[16]; private static VLC huff_quad_vlc[] = new VLC[2]; private static final int band_index_long[][] = new int[9][23]; private static final float is_table[][] = new float[2][16]; private static final float is_table_lsf[][][] = new float[2][2][16]; private static final float csa_table[][] = new float[8][4]; private static final int division_tab3[] = new int[1 << 6 ]; private static final int division_tab5[] = new int[1 << 8 ]; private static final int division_tab9[] = new int[1 << 11]; private static final int division_tabs[][] = { division_tab3, division_tab5, null, division_tab9 }; /* lower 2 bits: modulo 3, higher bits: shift */ private static final int scale_factor_modshift[] = new int[64]; /* [i][j]: 2^(-j/3) * FRAC_ONE * 2^(i+2) / (2^(i+2) - 1) */ private static final int scale_factor_mult[][] = new int[15][3]; private static final double ISQRT2 = 0.70710678118654752440; private static final int idxtab[] = { 3,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0 }; private void initStatic() { if (initializedTables) { return; } // scale factors table for layer 1/2 for (int i = 0; i < 64; i++) { // 1.0 (i = 3) is normalized to 2 ^ FRAC_BITS int shift = i / 3; int mod = i % 3; scale_factor_modshift[i] = mod | (shift << 2); } // scale factor multiply for layer 1 for (int i = 0; i < 15; i++) { int n = i + 2; int norm = (int) (((1L << n) * FRAC_ONE) / ((1 << n) - 1)); scale_factor_mult[i][0] = (int) (norm * 1.0f * 2.0f); scale_factor_mult[i][1] = (int) (norm * 0.7937005259f * 2.0f); scale_factor_mult[i][2] = (int) (norm * 0.6299605249f * 2.0f); } Mp3Dsp.synthInit(Mp3Dsp.mpa_synth_window); // Huffman decode tables for (int i = 1; i < 16; i++) { HuffTable h = Mp3Data.mpa_huff_tables[i]; int[] tmpBits = new int[512]; int[] tmpCodes = new int[512]; int xsize = h.xsize; int j = 0; for (int x = 0; x < xsize; x++) { for (int y = 0; y < xsize; y++) { tmpBits [(x << 5) | y | ((x != 0 && y != 0) ? 16 : 0)] = h.bits [j ]; tmpCodes[(x << 5) | y | ((x != 0 && y != 0) ? 16 : 0)] = h.codes[j++]; } } huff_vlc[i] = new VLC(); huff_vlc[i].initVLCSparse(7, 512, tmpBits, tmpCodes, null); } for (int i = 0; i < 2; i++) { huff_quad_vlc[i] = new VLC(); huff_quad_vlc[i].initVLCSparse(i == 0 ? 7 : 4, 16, mpa_quad_bits[i], mpa_quad_codes[i], null); } for (int i = 0; i < 9; i++) { int k = 0; for (int j = 0; j < 22; j++) { band_index_long[i][j] = k; k += band_size_long[i][j]; } band_index_long[i][22] = k; } Mp3Data.tableinit(); Mp3Dsp.initMpadspTabs(); for (int i = 0; i < 4; i++) { if (mp3_quant_bits[i] < 0) { for (int j = 0; j < (1 << (-mp3_quant_bits[i] + 1)); j++) { int val = j; int steps = Mp3Data.mp3_quant_steps[i]; int val1 = val % steps; val /= steps; int val2 = val % steps; int val3 = val / steps; division_tabs[i][j] = val1 + (val2 << 4) + (val3 << 8); } } } for (int i = 0; i < 7; i++) { float v; if (i != 6) { float f = (float) Math.tan(i * Math.PI / 12.0); v = f / (1f + f); } else { v = 1f; } is_table[0][ i] = v; is_table[1][6 - i] = v; } // invalid values for (int i = 7; i < 16; i++) { is_table[0][i] = 0f; is_table[1][i] = 0f; } for (int i = 0; i < 16; i++) { for (int j = 0; j < 2; j++) { int e = -(j + 1) * ((i + 1) >> 1); double f = pow(2.0, e / 4.0); int k = i & 1; is_table_lsf[j][k ^ 1][i] = (float) f; is_table_lsf[j][k ][i] = 1f; } } for (int i = 0; i < 8; i++) { float ci = ci_table[i]; float cs = (float) (1.0 / Math.sqrt(1.0 + ci * ci)); float ca = cs * ci; csa_table[i][0] = cs; csa_table[i][1] = ca; csa_table[i][2] = ca + cs; csa_table[i][3] = ca - cs; } initializedTables = true; } @Override public int init(int bytesPerFrame, int channels, int outputChannels, int codingMode) { initStatic(); ctx = new Context(); ctx.outputChannels = outputChannels; return 0; } private int mpaCheckHeader(int header) { // header if ((header & 0xFFE00000) != 0xFFE00000) { return -1; } // layer check if ((header & (3 << 17)) == 0) { return -1; } // bit rate if ((header & (0xF << 12)) == (0xF << 12)) { return -1; } // frequency if ((header & (3 << 10)) == (3 << 10)) { return -1; } return 0; } public static int decodeHeader(Mp3Header s, int header) { int mpeg25; if ((header & (1 << 20)) != 0) { s.lsf = (header & (1 << 19)) != 0 ? 0 : 1; mpeg25 = 0; } else { s.lsf = 1; mpeg25 = 1; } s.mpeg25 = mpeg25; s.version = (header >> 19) & 0x3; s.layer = 4 - ((header >> 17) & 3); // extract frequency int sampleRateIndex = (header >> 10) & 3; s.rawSampleRateIndex = sampleRateIndex; if (sampleRateIndex >= mp3_freq_tab.length) { sampleRateIndex = 0; } int sampleRate = mp3_freq_tab[sampleRateIndex] >> (s.lsf + mpeg25); sampleRateIndex += 3 * (s.lsf + mpeg25); s.sampleRateIndex = sampleRateIndex; s.errorProtection = ((header >> 16) & 1) ^ 1; s.sampleRate = sampleRate; int bitrateIndex = (header >> 12) & 0xF; s.bitrateIndex = bitrateIndex; int padding = (header >> 9) & 1; //extension = (header >> 8) & 1; s.mode = (header >> 6) & 3; s.modeExt = (header >> 4) & 3; //copyright = (header >> 3) & 1; //original = (header >> 2) & 1; //emphasis = header & 3; if (s.mode == MP3_MONO) { s.nbChannels = 1; } else { s.nbChannels = 2; } switch (s.layer) { case 1: s.maxSamples = 384; break; case 2: s.maxSamples = 1152; break; case 3: default: s.maxSamples = s.lsf != 0 ? 576 : 1152; break; } if (bitrateIndex != 0) { int frameSize = mp3_bitrate_tab[s.lsf][s.layer - 1][bitrateIndex]; s.bitRate = frameSize * 1000; switch (s.layer) { case 1: frameSize = (frameSize * 12000) / sampleRate; frameSize = (frameSize + padding) * 4; break; case 2: frameSize = (frameSize * 144000) / sampleRate; frameSize += padding; break; default: case 3: frameSize = (frameSize * 144000) / (sampleRate << s.lsf); frameSize += padding; break; } s.frameSize = frameSize; } else { // if no frame size computed, signal it return 1; } if (log.isDebugEnabled()) { log.debug(String.format("Mp3Header: %s", s)); } return 0; } private int decodeLayer1() { log.warn("Unimplemented MP3 Layer-1"); return 0; } private int decodeLayer2() { log.warn("Unimplemented MP3 Layer-2"); return 0; } private void initShortRegion(Granule g) { if (g.blockType == 2) { if (ctx.header.sampleRateIndex != 8) { g.regionSize[0] = 36 / 2; } else { g.regionSize[0] = 72 / 2; } } else { if (ctx.header.sampleRateIndex <= 2) { g.regionSize[0] = 36 / 2; } else if (ctx.header.sampleRateIndex != 8) { g.regionSize[0] = 54 / 2; } else { g.regionSize[0] = 108 / 2; } } g.regionSize[1] = 576 / 2; } private void initLongRegion(Granule g, int ra1, int ra2) { g.regionSize[0] = band_index_long[ctx.header.sampleRateIndex][ra1 + 1] >> 1; // should not overflow int l = Math.min(ra1 + ra2 + 2, 22); g.regionSize[1] = band_index_long[ctx.header.sampleRateIndex][l] >> 1; } private void computeBandIndexes(Granule g) { if (g.blockType == 2) { if (g.switchPoint != 0) { if (ctx.header.sampleRateIndex == 8) { log.warn(String.format("Unimplemented switch point in 8kHz")); } // if switched mode, we handle the 36 first samples as // long blocks. For 8000Hz, we handle the 72 first // exponents as long blocks if (ctx.header.sampleRateIndex <= 2) { g.longEnd = 8; } else { g.longEnd = 6; } g.shortStart = 3; } else { g.longEnd = 0; g.shortStart = 0; } } else { g.shortStart = 13; g.longEnd = 22; } } /** * Convert region offsets to region sizes and truncate * size to big_values. */ private void regionOffset2size(Granule g) { g.regionSize[2] = 576 / 2; for (int i = 0, j = 0; i < 3; i++) { int k = Math.min(g.regionSize[i], g.bigValues); g.regionSize[i] = k - j; j = k; } } private void lsfSfExpand(int[] slen, int sf, int n1, int n2, int n3) { if (n3 != 0) { slen[3] = sf % n3; sf /= n3; } else { slen[3] = 0; } if (n2 != 0) { slen[2] = sf % n2; sf /= n2; } else { slen[2] = 0; } if (n1 != 0) { slen[1] = sf % n1; sf /= n1; } else { slen[1] = 0; } slen[0] = sf; } public void exponentsFromScaleFactors(Granule g, int[] exponents) { int expPtr = 0; int gain = g.globalGain - 210; int shift = g.scalefacScale + 1; int[] gains = new int[3]; int[] bstab = band_size_long[ctx.header.sampleRateIndex]; int[] pretab = mpa_pretab[g.preflag]; for (int i = 0; i < g.longEnd; i++) { int v0 = gain - ((g.scaleFactors[i] + pretab[ i ]) << shift) + 400; int len = bstab[i]; for (int j = len; j > 0; j-- ) { exponents[expPtr++] = v0; } } if (g.shortStart < 13) { bstab = band_size_short[ctx.header.sampleRateIndex]; gains[0] = gain - (g.subblockGain[0] << 3); gains[1] = gain - (g.subblockGain[1] << 3); gains[2] = gain - (g.subblockGain[2] << 3); int k = g.longEnd; for (int i = g.shortStart; i < 13; i++ ) { int len = bstab[i]; for (int l = 0; l < 3; l++) { int v0 = gains[l] - (g.scaleFactors[k++] << shift) + 400; for (int j = len; j > 0; j--) { exponents[expPtr++] = v0; } } } } } /* compute value^(4/3) * 2^(exponent/4). It normalized to FRAC_BITS */ private int l3Unscale(int value, int exponent) { int e = Mp3Data.table_4_3_exp [4 * value + (exponent & 3)]; int m = Mp3Data.table_4_3_value[4 * value + (exponent & 3)]; e -= exponent >> 2; if (e > 31) { return 0; } m = (m + (1 << (e - 1))) >> e; return m; } private void huffmanDecode(Granule g, int[] exponents) { // low frequencies (called big values) int sIndex = 0; for (int i = 0; i < 3; i++) { int j = g.regionSize[i]; if (j == 0) { continue; } // select vlc table int k = g.tableSelect[i]; int l = mpa_huff_data[k][0]; int linbits = mpa_huff_data[k][1]; VLC vlc = huff_vlc[l]; if (l == 0) { Arrays.fill(g.sbHybrid, sIndex, sIndex + 2 * j, 0f); sIndex += 2 * j; continue; } // read huffcode and compute each couple for (; j > 0; j--) { int y = vlc.getVLC2(bb, 3); if (y == 0) { g.sbHybrid[sIndex] = 0; g.sbHybrid[sIndex + 1] = 0; sIndex += 2; continue; } int exponent = exponents[sIndex]; if ((y & 16) != 0) { int x = y >> 5; y = y & 0x0F; if (x < 15) { float v = expval_table[exponent][x]; if (bb.readBool()) { v = -v; } g.sbHybrid[sIndex] = v; } else { x += bb.read(linbits); float v = l3Unscale(x, exponent); if (bb.readBool()) { v = -v; } g.sbHybrid[sIndex] = v; } if (y < 15) { float v = expval_table[exponent][y];; if (bb.readBool()) { v = -v; } g.sbHybrid[sIndex + 1] = v; } else { y += bb.read(linbits); float v = l3Unscale(y, exponent); if (bb.readBool()) { v = -v; } g.sbHybrid[sIndex + 1] = v; } } else { int x = y >> 5; y = y & 0x0F; x += y; if (x < 15) { float v = expval_table[exponent][x];; if (bb.readBool()) { v = -v; } g.sbHybrid[sIndex + (y != 0 ? 1 : 0)] = v; } else { x += bb.read(linbits); float v = l3Unscale(y, exponent); if (bb.readBool()) { v = -v; } g.sbHybrid[sIndex + (y != 0 ? 1 : 0)] = v; } g.sbHybrid[sIndex + (y == 0 ? 1 : 0)] = 0; } sIndex += 2; } } // high frequencies VLC vlc = huff_quad_vlc[g.count1tableSelect]; int lastPos = 0; while (sIndex <= 572) { int pos = bb.getBitsRead(); if (pos >= g.granuleStartPosition + g.part23Length) { int overread = pos - (g.granuleStartPosition + g.part23Length); if (overread > 0 && lastPos > 0) { // Some encoders generate an incorrect size for this part. // We must go back to the last valid position. sIndex -= 4; bb.skip(lastPos - pos); if (log.isDebugEnabled()) { log.debug(String.format("Overread part23 by %d bits", overread)); } } break; } lastPos = pos; int code = vlc.getVLC2(bb); g.sbHybrid[sIndex + 0] = 0; g.sbHybrid[sIndex + 1] = 0; g.sbHybrid[sIndex + 2] = 0; g.sbHybrid[sIndex + 3] = 0; while (code != 0) { pos = sIndex + idxtab[code]; code ^= 8 >> idxtab[code]; float v = exp_table[exponents[pos]]; if (bb.readBool()) { v = -v; } g.sbHybrid[pos] = v; } sIndex += 4; } // skip extension bits int bitsLeft = g.granuleStartPosition + g.part23Length - bb.getBitsRead(); if (bitsLeft > 0) { bb.skip(bitsLeft); } Arrays.fill(g.sbHybrid, sIndex, 576, 0f); } private void computeStereo(Granule g0, Granule g1) { float isTab[][]; int sfMax; boolean nonZeroFoundShort[] = new boolean[3]; // intensity stereo if ((ctx.header.modeExt & MODE_EXT_I_STEREO) != 0) { if (ctx.header.lsf == 0) { isTab = is_table; sfMax = 7; } else { isTab = is_table_lsf[g1.scalefacCompress & 1]; sfMax = 16; } int tab0 = 576; int tab1 = 576; nonZeroFoundShort[0] = false; nonZeroFoundShort[1] = false; nonZeroFoundShort[2] = false; int k = (13 - g1.shortStart) * 3 + g1.longEnd - 3; for (int i = 12; i >= g1.shortStart; i--) { // for last band, use previous scale factor if (i != 11) { k -= 3; } int len = band_size_short[ctx.header.sampleRateIndex][i]; for (int l = 2; l >= 0; k--) { tab0 -= len; tab1 -= len; boolean doNonZero = nonZeroFoundShort[l]; int sf = 0; if (!doNonZero) { // test if non zero band. If so, stop doing i-stereo for (int j = 0; j < len; j++) { if (g1.sbHybrid[tab1 + j] != 0f) { nonZeroFoundShort[l] = true; doNonZero = true; break; } } if (!doNonZero) { sf = g1.scaleFactors[k + l]; if (sf >= sfMax) { doNonZero = true; } } } if (!doNonZero) { float v1 = isTab[0][sf]; float v2 = isTab[1][sf]; for (int j = 0; j < len; j++) { float tmp0 = g0.sbHybrid[tab0 + j]; g0.sbHybrid[tab0 + j] = tmp0 * v1; g1.sbHybrid[tab1 + j] = tmp0 * v2; } } else { if ((ctx.header.modeExt & MODE_EXT_MS_STEREO) != 0) { // lower part of the spectrum: do ms stereo if enabled for (int j = 0; j < len; j++) { float tmp0 = g0.sbHybrid[tab0 + j]; float tmp1 = g1.sbHybrid[tab1 + j]; g0.sbHybrid[tab0 + j] = (float) ((tmp0 + tmp1) * ISQRT2); g1.sbHybrid[tab1 + j] = (float) ((tmp0 - tmp1) * ISQRT2); } } } } } boolean nonZeroFound = nonZeroFoundShort[0] || nonZeroFoundShort[1] || nonZeroFoundShort[2]; for (int i = g1.longEnd - 1; i >= 0; i--) { int len = band_size_long[ctx.header.sampleRateIndex][i]; tab0 -= len; tab1 -= len; // test if non zero band. If so, stop doing i-stereo if (!nonZeroFound) { for (int j = 0; j < len; j++) { if (g1.sbHybrid[tab1 + j] != 0f) { nonZeroFound = true; break; } } } int sf = 0; if (!nonZeroFound) { // for last band, use previous scale factor k = (i == 21) ? 20 : i; sf = g1.scaleFactors[k]; if (sf >= sfMax) { nonZeroFound = true; } } if (!nonZeroFound) { float v1 = isTab[0][sf]; float v2 = isTab[1][sf]; for (int j = 0; j < len; j++) { float tmp0 = g0.sbHybrid[tab0 + j]; g0.sbHybrid[tab0 + j] = tmp0 * v1; g1.sbHybrid[tab1 + j] = tmp0 * v2; } } else { if ((ctx.header.modeExt & MODE_EXT_MS_STEREO) != 0) { // lower part of the spectrum: do ms stereo if enabled for (int j = 0; j < len; j++) { float tmp0 = g0.sbHybrid[tab0 + j]; float tmp1 = g1.sbHybrid[tab1 + j]; g0.sbHybrid[tab0 + j] = (float) ((tmp0 + tmp1) * ISQRT2); g1.sbHybrid[tab1 + j] = (float) ((tmp0 - tmp1) * ISQRT2); } } } } } else if ((ctx.header.modeExt & MODE_EXT_MS_STEREO) != 0) { // ms stereo ONLY // NOTE: the 1/sqrt(2) normalization factor is included in the global gain FloatDSP.butterflies(g0.sbHybrid, 0, g1.sbHybrid, 0, 576); } } /* Reorder short blocks from bitstream order to interleaved order. It would be faster to do it in parsing, but the code would be far more complicated */ private void reorderBlock(Granule g) { if (g.blockType != 2) { return; } final float tmp[] = new float[576]; int ptr; if (g.switchPoint != 0) { if (ctx.header.sampleRateIndex != 8) { ptr = 36; } else { ptr = 72; } } else { ptr = 0; } for (int i = g.shortStart; i < 13; i++) { int len = band_size_short[ctx.header.sampleRateIndex][i]; int ptr1 = ptr; int dst = 0; for (int j = len; j > 0; j--) { tmp[dst++] = g.sbHybrid[ptr + 0 * len]; tmp[dst++] = g.sbHybrid[ptr + 1 * len]; tmp[dst++] = g.sbHybrid[ptr + 2 * len]; ptr++; } ptr += 2 * len; System.arraycopy(tmp, 0, g.sbHybrid, ptr1, 3 * len); } } private void AA(float[] ptr, int ptrOffset, int j) { float tmp0 = ptr[ptrOffset - 1 - j]; float tmp1 = ptr[ptrOffset + j]; ptr[ptrOffset - 1 - j] = tmp0 * csa_table[j][0] - tmp1 * csa_table[j][1]; ptr[ptrOffset + j] = tmp0 * csa_table[j][1] + tmp1 * csa_table[j][0]; } private void computeAntialias(Granule g) { int n; // we antialias only "long" bands if (g.blockType == 2) { if (g.switchPoint == 0) { return; } n = 1; } else { n = SBLIMIT - 1; } int ptr = 18; for (int i = n; i > 0; i--) { AA(g.sbHybrid, ptr, 0); AA(g.sbHybrid, ptr, 1); AA(g.sbHybrid, ptr, 2); AA(g.sbHybrid, ptr, 3); AA(g.sbHybrid, ptr, 4); AA(g.sbHybrid, ptr, 5); AA(g.sbHybrid, ptr, 6); AA(g.sbHybrid, ptr, 7); ptr += 18; } } private static final float C3 = (float) (0.86602540378443864676/2); private static final float C4 = (float) (0.70710678118654752439/2); //0.5 / cos(pi*(9)/36) private static final float C5 = (float) (0.51763809020504152469/2); //0.5 / cos(pi*(5)/36) private static final float C6 = (float) (1.93185165257813657349/4); //0.5 / cos(pi*(15)/36) /* 12 points IMDCT. We compute it "by hand" by factorizing obvious cases. */ private void imdct12(float[] out, int outOffset, float[] in, int inOffset) { float in0 = in[inOffset + 0 * 3]; float in1 = in[inOffset + 1 * 3] + in[inOffset + 0 * 3]; float in2 = in[inOffset + 2 * 3] + in[inOffset + 1 * 3]; float in3 = in[inOffset + 3 * 3] + in[inOffset + 2 * 3]; float in4 = in[inOffset + 4 * 3] + in[inOffset + 3 * 3]; float in5 = in[inOffset + 5 * 3] + in[inOffset + 4 * 3]; in5 += in3; in3 += in1; in2 = in2 * C3 * 2f; in3 = in3 * C3 * 4f; float t1 = in0 - in4; float t2 = (in1 - in5) * C4 * 2f; out[outOffset + 7] = t1 + t2; out[outOffset + 10] = t1 + t2; out[outOffset + 1] = t1 - t2; out[outOffset + 4] = t1 - t2; in0 += in4 * 0.5f; in4 = in0 + in2; in5 += 2f * in1; in1 = (in5 + in3) * C5; out[outOffset + 8] = in4 + in1; out[outOffset + 9] = in4 + in1; out[outOffset + 2] = in4 - in1; out[outOffset + 3] = in4 - in1; in0 -= in2; in5 = (in5 - in3) * C6 * 2f; out[outOffset + 0] = in0 - in5; out[outOffset + 5] = in0 - in5; out[outOffset + 6] = in0 + in5; out[outOffset + 11] = in0 + in5; } private void computeImdct(Granule g, float[] sbSamples, int sbSamplesOffset, float[] mdctbuf) { float out2[] = new float[12]; // find last non zero block int ptr = 576; int ptr1 = 2 * 18; float [] p = g.sbHybrid; while (ptr >= ptr1) { ptr -= 6; if (p[ptr] != 0f || p[ptr + 1] != 0f || p[ptr + 2] != 0f || p[ptr + 3] != 0f || p[ptr + 4] != 0f || p[ptr + 5] != 0f) { break; } } int sblimit = ptr / 18 + 1; int mdctLongEnd; if (g.blockType == 2) { if (g.switchPoint != 0) { mdctLongEnd = 2; } else { mdctLongEnd = 0; } } else { mdctLongEnd = sblimit; } Mp3Dsp.imdct36Blocks(sbSamples, sbSamplesOffset, mdctbuf, 0, g.sbHybrid, 0, mdctLongEnd, g.switchPoint, g.blockType); int buf = 4 * 18 * (mdctLongEnd >> 2) + (mdctLongEnd & 3); ptr = 18 * mdctLongEnd; for (int j = mdctLongEnd; j < sblimit; j++) { // select frequency inversion float win[] = mdct_win[2 + (4 & -(j & 1))]; int outPtr = j; for (int i = 0; i < 6; i++) { sbSamples[outPtr] = mdctbuf[buf + 4 * i]; outPtr += SBLIMIT; } imdct12(out2, 0, g.sbHybrid, ptr + 0); for (int i = 0; i < 6; i++) { sbSamples[outPtr] = out2[i] * win[i] + mdctbuf[buf + 4 * (i + 6 * 1)]; mdctbuf[buf + 4 * (i + 6 * 2)] = out2[i + 6] * win[i + 6]; outPtr += SBLIMIT; } imdct12(out2, 0, g.sbHybrid, ptr + 1); for (int i = 0; i < 6; i++) { sbSamples[outPtr] = out2[i] * win[i] + mdctbuf[buf + 4 * (i + 6 * 2)]; mdctbuf[buf + 4 * (i + 6 * 0)] = out2[i + 6] * win[i + 6]; outPtr += SBLIMIT; } imdct12(out2, 0, g.sbHybrid, ptr + 2); for (int i = 0; i < 6; i++) { mdctbuf[buf + 4 * (i + 6 * 0)] = out2[i ] * win[i ] + mdctbuf[buf + 4 * (i + 6 * 0)]; mdctbuf[buf + 4 * (i + 6 * 1)] = out2[i + 6] * win[i + 6]; mdctbuf[buf + 4 * (i + 6 * 2)] = 0f; } ptr += 18; buf += (j & 3) != 3 ? 1 : (4 * 18 - 3); } // zero bands for (int j = sblimit; j < SBLIMIT; j++) { // overlap int outPtr = j; for (int i = 0; i < 18; i++) { sbSamples[outPtr] = mdctbuf[buf + 4 * i]; mdctbuf[buf + 4 * i] = 0f; outPtr += SBLIMIT; } buf += (j & 3) != 3 ? 1 : (4 * 18 - 3); } } // main layer3 decoding function private int decodeLayer3(int frameStart) { int mainDataBegin; int nbGranules; int[] exponents = new int[576]; Mp3Header s = ctx.header; // read side info if (s.lsf != 0) { mainDataBegin = br.read(8); br.skip(s.nbChannels); nbGranules = 1; } else { mainDataBegin = br.read(9); if (s.nbChannels == 2) { br.skip(3); } else { br.skip(5); } nbGranules = 2; for (int ch = 0; ch < s.nbChannels; ch++) { ctx.granules[ch][0].scfsi = 0; // all scale factors are transmitted ctx.granules[ch][1].scfsi = br.read(4); } } for (int gr = 0; gr < nbGranules; gr++) { for (int ch = 0; ch < s.nbChannels; ch++) { Granule g = ctx.granules[ch][gr]; g.part23Length = br.read(12); g.bigValues = br.read(9); if (g.bigValues > 288) { log.error(String.format("bigValues too big %d", g.bigValues)); return MP3_ERROR; } g.globalGain = br.read(8); // if MS stereo only is selected, we precompute the // 1/sqrt(2) renormalization factor if ((s.modeExt & (MODE_EXT_MS_STEREO | MODE_EXT_I_STEREO)) == MODE_EXT_MS_STEREO) { g.globalGain -= 2; } if (s.lsf != 0) { g.scalefacCompress = br.read(9); } else { g.scalefacCompress = br.read(4); } boolean blocksplitFlag = br.readBool(); if (blocksplitFlag) { g.blockType = br.read(2); if (g.blockType == 0) { log.error(String.format("invalid block type")); return MP3_ERROR; } g.switchPoint = br.read1(); for (int i = 0; i < 2; i++) { g.tableSelect[i] = br.read(5); } for (int i = 0; i < 3; i++) { g.subblockGain[i] = br.read(3); } initShortRegion(g); } else { g.blockType = 0; g.switchPoint = 0; for (int i = 0; i < 3; i++) { g.tableSelect[i] = br.read(5); } // compute Huffman coded region sizes int regionAddress1 = br.read(4); int regionAddress2 = br.read(3); initLongRegion(g, regionAddress1, regionAddress2); } regionOffset2size(g); computeBandIndexes(g); g.preflag = 0; if (s.lsf == 0) { g.preflag = br.read1(); } g.scalefacScale = br.read1(); g.count1tableSelect = br.read1(); } } if (ctx.aduMode == 0) { int currentPosition = br.getBytesRead(); int copyLength = ctx.header.frameSize - (currentPosition - frameStart); int bitsToSkip = bb.getBitsWritten() - bb.getBitsRead() - (mainDataBegin << 3); for (int i = 0; i < copyLength; i++) { bb.writeByte(br.readByte()); } bb.skip(bitsToSkip); } for (int gr = 0; gr < nbGranules; gr++) { for (int ch = 0; ch < s.nbChannels; ch++) { Granule g = ctx.granules[ch][gr]; g.granuleStartPosition = bb.getBitsRead(); if (s.lsf == 0) { // MPEG1 scale factors int slen1 = slen_table[0][g.scalefacCompress]; int slen2 = slen_table[1][g.scalefacCompress]; if (g.blockType == 2) { int n = g.switchPoint != 0 ? 17 : 18; int j = 0; if (slen1 != 0) { for (int i = 0; i < n; i++) { g.scaleFactors[j++] = bb.read(slen1); } } else { for (int i = 0; i < n; i++) { g.scaleFactors[j++] = 0; } } if (slen2 != 0) { for (int i = 0; i < 18; i++) { g.scaleFactors[j++] = bb.read(slen2); } for (int i = 0; i < 3; i++) { g.scaleFactors[j++] = 0; } } else { for (int i = 0; i < 21; i++) { g.scaleFactors[j++] = 0; } } } else { int sc[] = ctx.granules[ch][0].scaleFactors; int j = 0; for (int k = 0; k < 4; k++) { int n = (k == 0 ? 6 : 5); if ((g.scfsi & (0x8 >> k)) == 0) { int slen = (k < 2 ? slen1 : slen2); if (slen != 0) { for (int i = 0; i < n; i++) { g.scaleFactors[j++] = bb.read(slen); } } else { for (int i = 0; i < n; i++) { g.scaleFactors[j++] = 0; } } } else { // simple copy from last granule for (int i = 0; i < n; i++) { g.scaleFactors[j] = sc[j]; j++; } } } g.scaleFactors[j++] = 0; } } else { int tindex; int tindex2; int[] slen = new int[4]; // LSF scale factors if (g.blockType == 2) { tindex = g.switchPoint != 0 ? 2 : 1; } else { tindex = 0; } int sf = g.scalefacCompress; if ((s.modeExt & MODE_EXT_I_STEREO) != 0 && ch == 1) { // intensity stereo case sf >>= 1; if (sf < 180) { lsfSfExpand(slen, sf, 6, 6, 0); tindex2 = 3; } else if (sf < 244) { lsfSfExpand(slen, sf - 180, 4, 4, 0); tindex2 = 4; } else { lsfSfExpand(slen, sf - 244, 3, 0, 0); tindex2 = 5; } } else { // normal case if (sf < 400) { lsfSfExpand(slen, sf, 5, 4, 4); tindex2 = 0; } else if (sf < 500) { lsfSfExpand(slen, sf - 400, 5, 4, 0); tindex2 = 1; } else { lsfSfExpand(slen, sf - 500, 3, 0, 0); tindex2 = 2; g.preflag = 1; } } int j = 0; for (int k = 0; k < 4; k++) { int n = lsf_nsf_table[tindex2][tindex][k]; int sl = slen[k]; if (sl != 0) { for (int i = 0; i < n; i++) { g.scaleFactors[j++] = bb.read(sl); } } else { for (int i = 0; i < n; i++) { g.scaleFactors[j++] = 0; } } } for (; j < 40; j++) { g.scaleFactors[j] = 0; } } exponentsFromScaleFactors(g, exponents); // read Huffman coded residue huffmanDecode(g, exponents); } if (s.mode == MP3_JSTEREO) { computeStereo(ctx.granules[0][gr], ctx.granules[1][gr]); } for (int ch = 0; ch < s.nbChannels; ch++) { Granule g = ctx.granules[ch][gr]; reorderBlock(g); computeAntialias(g); computeImdct(g, ctx.sbSamples[ch], 18 * gr * SBLIMIT, ctx.mdctBuf[ch]); } } return nbGranules * 18; } private int decodeFrame(int frameStart) { int nbFrames; if (ctx.header.errorProtection != 0) { br.skip(16); } switch (ctx.header.layer) { case 1: nbFrames = decodeLayer1(); break; case 2: nbFrames = decodeLayer2(); break; case 3: default: nbFrames = decodeLayer3(frameStart); break; } if (nbFrames < 0) { return nbFrames; } // get output buffer if (ctx.samples == null) { ctx.samples = new float[ctx.header.nbChannels][ctx.header.maxSamples]; } // apply the synthesis filter for (int ch = 0; ch < ctx.header.nbChannels; ch++) { int sampleStride = 1; int samplesPtr = 0; for (int i = 0; i < nbFrames; i++) { Mp3Dsp.synthFilter(ctx, ch, ctx.samples[ch], samplesPtr, sampleStride, ctx.sbSamples[ch], i * SBLIMIT); samplesPtr += 32 * sampleStride; } } return nbFrames * 32 * 4 * ctx.header.nbChannels; } @Override public int decode(int inputAddr, int inputLength, int outputAddr) { br = new BitReader(inputAddr, inputLength); ctx.br = br; int skippedBytes = 0; while (br.peek(8) == 0) { br.skip(8); skippedBytes++; } if (br.getBitsLeft() < HEADER_SIZE * 8) { return MP3_ERROR; } int frameStart = br.getBytesRead(); int header = br.read(32); if (mpaCheckHeader(header) < 0) { log.error(String.format("Header missing")); return MP3_ERROR; } if (decodeHeader(ctx.header, header) == 1) { // free format: prepare to compute frame size ctx.header.frameSize = -1; return MP3_ERROR; } int ret = decodeFrame(frameStart); if (ret < 0) { return ret; } CodecUtils.writeOutput(ctx.samples, outputAddr, ctx.header.maxSamples, ctx.header.nbChannels, ctx.outputChannels); return ctx.header.frameSize + skippedBytes; } @Override public int getNumberOfSamples() { return ctx.header.maxSamples; } public Mp3Header getMp3Header() { return ctx.header; } }