public FilterBank(bool smallFrames, int channels) { if (smallFrames) { length = WINDOW_SMALL_LEN_LONG; shortLen = WINDOW_SMALL_LEN_SHORT; LONG_WINDOWS = new[] { SINE_960, KBD_960 }; SHORT_WINDOWS = new[] { SINE_120, KBD_120 }; } else { length = WINDOW_LEN_LONG; shortLen = WINDOW_LEN_SHORT; LONG_WINDOWS = new[] { SINE_1024, KBD_1024 }; SHORT_WINDOWS = new[] { SINE_128, KBD_128 }; } mid = (length - shortLen) / 2; trans = shortLen / 2; mdctShort = new MDCT(shortLen * 2); mdctLong = new MDCT(length * 2); overlaps = Enumerable.Range(0, channels).Select(x => new float[length]).ToArray(); buf = new float[2 * length]; }
// fixme: test the perf of this alternate implementation //int logSum(int a, int b) //{ // return log2(pow(4, a) + pow(4, b)) / 2; //} internal static void surround_analysis <T>(CeltMode celt_mode, T[] pcm, int pcm_ptr, int[] bandLogE, int[] mem, int[] preemph_mem, int len, int overlap, int channels, int rate, opus_copy_channel_in_func <T> copy_channel_in ) { int c; int i; int LM; int[] pos = { 0, 0, 0, 0, 0, 0, 0, 0 }; int upsample; int frame_size; int channel_offset; int[][] bandE = Arrays.InitTwoDimensionalArray <int>(1, 21); int[][] maskLogE = Arrays.InitTwoDimensionalArray <int>(3, 21); int[] input; short[] x; int[][] freq; upsample = CeltCommon.resampling_factor(rate); frame_size = len * upsample; for (LM = 0; LM < celt_mode.maxLM; LM++) { if (celt_mode.shortMdctSize << LM == frame_size) { break; } } input = new int[frame_size + overlap]; x = new short[len]; freq = Arrays.InitTwoDimensionalArray <int>(1, frame_size); channel_pos(channels, pos); for (c = 0; c < 3; c++) { for (i = 0; i < 21; i++) { maskLogE[c][i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/; } } for (c = 0; c < channels; c++) { Array.Copy(mem, c * overlap, input, 0, overlap); copy_channel_in(x, 0, 1, pcm, pcm_ptr, channels, c, len); BoxedValueInt boxed_preemph = new BoxedValueInt(preemph_mem[c]); CeltCommon.celt_preemphasis(x, input, overlap, frame_size, 1, upsample, celt_mode.preemph, boxed_preemph, 0); preemph_mem[c] = boxed_preemph.Val; MDCT.clt_mdct_forward( celt_mode.mdct, input, 0, freq[0], 0, celt_mode.window, overlap, celt_mode.maxLM - LM, 1); if (upsample != 1) { int bound = len; for (i = 0; i < bound; i++) { freq[0][i] *= upsample; } for (; i < frame_size; i++) { freq[0][i] = 0; } } Bands.compute_band_energies(celt_mode, freq, bandE, 21, 1, LM); QuantizeBands.amp2Log2(celt_mode, 21, 21, bandE[0], bandLogE, 21 * c, 1); /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */ for (i = 1; i < 21; i++) { bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i - 1] - ((short)(0.5 + (1.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/); } for (i = 19; i >= 0; i--) { bandLogE[21 * c + i] = Inlines.MAX16(bandLogE[21 * c + i], bandLogE[21 * c + i + 1] - ((short)(0.5 + (2.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(2.0f, CeltConstants.DB_SHIFT)*/); } if (pos[c] == 1) { for (i = 0; i < 21; i++) { maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21 * c + i]); } } else if (pos[c] == 3) { for (i = 0; i < 21; i++) { maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21 * c + i]); } } else if (pos[c] == 2) { for (i = 0; i < 21; i++) { maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21 * c + i] - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/); maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21 * c + i] - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/); } } Array.Copy(input, frame_size, mem, c * overlap, overlap); } for (i = 0; i < 21; i++) { maskLogE[1][i] = Inlines.MIN32(maskLogE[0][i], maskLogE[2][i]); } channel_offset = Inlines.HALF16(Inlines.celt_log2(((int)(0.5 + (2.0f) * (((int)1) << (14)))) /*Inlines.QCONST32(2.0f, 14)*/ / (channels - 1))); for (c = 0; c < 3; c++) { for (i = 0; i < 21; i++) { maskLogE[c][i] += channel_offset; } } for (c = 0; c < channels; c++) { int[] mask; if (pos[c] != 0) { mask = maskLogE[pos[c] - 1]; for (i = 0; i < 21; i++) { bandLogE[21 * c + i] = bandLogE[21 * c + i] - mask[i]; } } else { for (i = 0; i < 21; i++) { bandLogE[21 * c + i] = 0; } } } }