/// <summary> /// Encode quantization indices of excitation /// </summary> /// <param name="psRangeEnc">I/O compressor data structure</param> /// <param name="signalType">I Signal type</param> /// <param name="quantOffsetType">I quantOffsetType</param> /// <param name="pulses">I quantization indices</param> /// <param name="frame_length">I Frame length</param> internal static void silk_encode_pulses( EntropyCoder psRangeEnc, int signalType, int quantOffsetType, sbyte[] pulses, int frame_length) { int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; int abs_q, minSumBits_Q5, sumBits_Q5; int[] abs_pulses; int[] sum_pulses; int[] nRshifts; int[] pulses_comb = new int[8]; int abs_pulses_ptr; int pulses_ptr; byte[] nBits_ptr; Arrays.MemSetInt(pulses_comb, 0, 8); /****************************/ /* Prepare for shell coding */ /****************************/ /* Calculate number of shell blocks */ Inlines.OpusAssert(1 << SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH == SilkConstants.SHELL_CODEC_FRAME_LENGTH); iter = Inlines.silk_RSHIFT(frame_length, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH); if (iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH < frame_length) { Inlines.OpusAssert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */ iter++; Arrays.MemSetWithOffset <sbyte>(pulses, 0, frame_length, SilkConstants.SHELL_CODEC_FRAME_LENGTH); } /* Take the absolute value of the pulses */ abs_pulses = new int[iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH]; Inlines.OpusAssert((SilkConstants.SHELL_CODEC_FRAME_LENGTH & 3) == 0); // unrolled loop for (i = 0; i < iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH; i += 4) { abs_pulses[i + 0] = (int)Inlines.silk_abs(pulses[i + 0]); abs_pulses[i + 1] = (int)Inlines.silk_abs(pulses[i + 1]); abs_pulses[i + 2] = (int)Inlines.silk_abs(pulses[i + 2]); abs_pulses[i + 3] = (int)Inlines.silk_abs(pulses[i + 3]); } /* Calc sum pulses per shell code frame */ sum_pulses = new int[iter]; nRshifts = new int[iter]; abs_pulses_ptr = 0; for (i = 0; i < iter; i++) { nRshifts[i] = 0; while (true) { /* 1+1 . 2 */ scale_down = combine_and_check(pulses_comb, 0, abs_pulses, abs_pulses_ptr, Tables.silk_max_pulses_table[0], 8); /* 2+2 . 4 */ scale_down += combine_and_check(pulses_comb, pulses_comb, Tables.silk_max_pulses_table[1], 4); /* 4+4 . 8 */ scale_down += combine_and_check(pulses_comb, pulses_comb, Tables.silk_max_pulses_table[2], 2); /* 8+8 . 16 */ scale_down += combine_and_check(sum_pulses, i, pulses_comb, 0, Tables.silk_max_pulses_table[3], 1); if (scale_down != 0) { /* We need to downscale the quantization signal */ nRshifts[i]++; for (k = abs_pulses_ptr; k < abs_pulses_ptr + SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++) { abs_pulses[k] = Inlines.silk_RSHIFT(abs_pulses[k], 1); } } else { /* Jump out of while(1) loop and go to next shell coding frame */ break; } } abs_pulses_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH; } /**************/ /* Rate level */ /**************/ /* find rate level that leads to fewest bits for coding of pulses per block info */ minSumBits_Q5 = int.MaxValue; for (k = 0; k < SilkConstants.N_RATE_LEVELS - 1; k++) { nBits_ptr = Tables.silk_pulses_per_block_BITS_Q5[k]; sumBits_Q5 = Tables.silk_rate_levels_BITS_Q5[signalType >> 1][k]; for (i = 0; i < iter; i++) { if (nRshifts[i] > 0) { sumBits_Q5 += nBits_ptr[SilkConstants.SILK_MAX_PULSES + 1]; } else { sumBits_Q5 += nBits_ptr[sum_pulses[i]]; } } if (sumBits_Q5 < minSumBits_Q5) { minSumBits_Q5 = sumBits_Q5; RateLevelIndex = k; } } psRangeEnc.enc_icdf(RateLevelIndex, Tables.silk_rate_levels_iCDF[signalType >> 1], 8); /***************************************************/ /* Sum-Weighted-Pulses Encoding */ /***************************************************/ for (i = 0; i < iter; i++) { if (nRshifts[i] == 0) { psRangeEnc.enc_icdf(sum_pulses[i], Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8); } else { psRangeEnc.enc_icdf(SilkConstants.SILK_MAX_PULSES + 1, Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8); for (k = 0; k < nRshifts[i] - 1; k++) { psRangeEnc.enc_icdf(SilkConstants.SILK_MAX_PULSES + 1, Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8); } psRangeEnc.enc_icdf(sum_pulses[i], Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], 8); } } /******************/ /* Shell Encoding */ /******************/ for (i = 0; i < iter; i++) { if (sum_pulses[i] > 0) { ShellCoder.silk_shell_encoder(psRangeEnc, abs_pulses, i * SilkConstants.SHELL_CODEC_FRAME_LENGTH); } } /****************/ /* LSB Encoding */ /****************/ for (i = 0; i < iter; i++) { if (nRshifts[i] > 0) { pulses_ptr = i * SilkConstants.SHELL_CODEC_FRAME_LENGTH; nLS = nRshifts[i] - 1; for (k = 0; k < SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++) { abs_q = (sbyte)Inlines.silk_abs(pulses[pulses_ptr + k]); for (j = nLS; j > 0; j--) { bit = Inlines.silk_RSHIFT(abs_q, j) & 1; psRangeEnc.enc_icdf(bit, Tables.silk_lsb_iCDF, 8); } bit = abs_q & 1; psRangeEnc.enc_icdf(bit, Tables.silk_lsb_iCDF, 8); } } } /****************/ /* Encode signs */ /****************/ CodeSigns.silk_encode_signs(psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses); }
/*********************************************/ /* Decode quantization indices of excitation */ /*********************************************/ internal static void silk_decode_pulses( EntropyCoder psRangeDec, /* I/O Compressor data structure */ short[] pulses, /* O Excitation signal */ int signalType, /* I Sigtype */ int quantOffsetType, /* I quantOffsetType */ int frame_length /* I Frame length */ ) { int i, j, k, iter, abs_q, nLS, RateLevelIndex; int[] sum_pulses = new int[SilkConstants.MAX_NB_SHELL_BLOCKS]; int[] nLshifts = new int[SilkConstants.MAX_NB_SHELL_BLOCKS]; int pulses_ptr; /*********************/ /* Decode rate level */ /*********************/ RateLevelIndex = psRangeDec.dec_icdf(Tables.silk_rate_levels_iCDF[signalType >> 1], 8); /* Calculate number of shell blocks */ Inlines.OpusAssert(1 << SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH == SilkConstants.SHELL_CODEC_FRAME_LENGTH); iter = Inlines.silk_RSHIFT(frame_length, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH); if (iter * SilkConstants.SHELL_CODEC_FRAME_LENGTH < frame_length) { Inlines.OpusAssert(frame_length == 12 * 10); /* Make sure only happens for 10 ms @ 12 kHz */ iter++; } /***************************************************/ /* Sum-Weighted-Pulses Decoding */ /***************************************************/ for (i = 0; i < iter; i++) { nLshifts[i] = 0; sum_pulses[i] = psRangeDec.dec_icdf(Tables.silk_pulses_per_block_iCDF[RateLevelIndex], 8); /* LSB indication */ while (sum_pulses[i] == SilkConstants.SILK_MAX_PULSES + 1) { nLshifts[i]++; /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */ sum_pulses[i] = psRangeDec.dec_icdf( Tables.silk_pulses_per_block_iCDF[SilkConstants.N_RATE_LEVELS - 1], (nLshifts[i] == 10 ? 1 : 0), 8); } } /***************************************************/ /* Shell decoding */ /***************************************************/ for (i = 0; i < iter; i++) { if (sum_pulses[i] > 0) { ShellCoder.silk_shell_decoder(pulses, Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH), psRangeDec, sum_pulses[i]); } else { Arrays.MemSetWithOffset <short>(pulses, 0, Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH), SilkConstants.SHELL_CODEC_FRAME_LENGTH); } } /***************************************************/ /* LSB Decoding */ /***************************************************/ for (i = 0; i < iter; i++) { if (nLshifts[i] > 0) { nLS = nLshifts[i]; pulses_ptr = Inlines.silk_SMULBB(i, SilkConstants.SHELL_CODEC_FRAME_LENGTH); for (k = 0; k < SilkConstants.SHELL_CODEC_FRAME_LENGTH; k++) { abs_q = pulses[pulses_ptr + k]; for (j = 0; j < nLS; j++) { abs_q = Inlines.silk_LSHIFT(abs_q, 1); abs_q += psRangeDec.dec_icdf(Tables.silk_lsb_iCDF, 8); } pulses[pulses_ptr + k] = (short)(abs_q); } /* Mark the number of pulses non-zero for sign decoding. */ sum_pulses[i] |= nLS << 5; } } /****************************************/ /* Decode and add signs to pulse signal */ /****************************************/ CodeSigns.silk_decode_signs(psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses); }