/// <summary> /// Decode mid/side predictors /// </summary> /// <param name="psRangeDec">I/O Compressor data structure</param> /// <param name="pred_Q13">O Predictors</param> internal static void silk_stereo_decode_pred( EntropyCoder psRangeDec, int[] pred_Q13) { int n; int[][] ix = Arrays.InitTwoDimensionalArray <int>(2, 3); int low_Q13, step_Q13; // Entropy decoding n = psRangeDec.dec_icdf(Tables.silk_stereo_pred_joint_iCDF, 8); ix[0][2] = Inlines.silk_DIV32_16(n, 5); ix[1][2] = n - 5 * ix[0][2]; for (n = 0; n < 2; n++) { ix[n][0] = psRangeDec.dec_icdf(Tables.silk_uniform3_iCDF, 8); ix[n][1] = psRangeDec.dec_icdf(Tables.silk_uniform5_iCDF, 8); } // Dequantize for (n = 0; n < 2; n++) { ix[n][0] += 3 * ix[n][2]; low_Q13 = Tables.silk_stereo_pred_quant_Q13[ix[n][0]]; step_Q13 = Inlines.silk_SMULWB(Tables.silk_stereo_pred_quant_Q13[ix[n][0] + 1] - low_Q13, ((int)((0.5f / SilkConstants.STEREO_QUANT_SUB_STEPS) * ((long)1 << (16)) + 0.5)) /*Inlines.SILK_CONST(0.5f / SilkConstants.STEREO_QUANT_SUB_STEPS, 16)*/); pred_Q13[n] = Inlines.silk_SMLABB(low_Q13, step_Q13, 2 * ix[n][1] + 1); } /* Subtract second from first predictor (helps when actually applying these) */ pred_Q13[0] -= pred_Q13[1]; }
/// <summary> /// Decode mid-only flag /// </summary> /// <param name="psRangeDec">I/O Compressor data structure</param> /// <param name="decode_only_mid">O Flag that only mid channel has been coded</param> internal static void silk_stereo_decode_mid_only( EntropyCoder psRangeDec, BoxedValueInt decode_only_mid ) { /* Decode flag that only mid channel is coded */ decode_only_mid.Val = psRangeDec.dec_icdf(Tables.silk_stereo_only_code_mid_iCDF, 8); }
private sbyte DecodeSign(ContextVector contextVector, int x, int y) { contextVector.GetSignCodingContextLabelAndXorBit(out int contextLabel, out int xorBit); var cx = GetContext(contextLabel); var d = EntropyCoder.DecodeNextBit(cx); var signBit = d ^ xorBit; var sign = (sbyte)((signBit == 0) ? 1 : -1); UpdateNeighbourContextVectors(x, y, sign); return(sign); }
internal static void encode_split( EntropyCoder psRangeEnc, /* I/O compressor data structure */ int p_child1, /* I pulse amplitude of first child subframe */ int p, /* I pulse amplitude of current subframe */ byte[] shell_table /* I table of shell cdfs */ ) { if (p > 0) { psRangeEnc.enc_icdf(p_child1, shell_table, Tables.silk_shell_code_table_offsets[p], 8); } }
public static byte[] EncodeJPEG(Image jpgImage) { Tiler imgtiler; ForwCompTransf fctransf; ImgDataConverter converter; EncoderSpecs encSpec; ForwardWT dwt; Quantizer quant; ROIScaler rois; EntropyCoder ecoder; PostCompRateAllocator ralloc; HeaderEncoder headenc; CodestreamWriter bwriter; float rate = Single.MaxValue; ImgReaderGDI imgsrc = new ImgReaderGDI(jpgImage); imgtiler = new Tiler(imgsrc, 0, 0, 0, 0, jpgImage.Width, jpgImage.Height); int ntiles = imgtiler.getNumTiles(); encSpec = new EncoderSpecs(ntiles, 3, imgsrc, pl); fctransf = new ForwCompTransf(imgtiler, encSpec); converter = new ImgDataConverter(fctransf); dwt = ForwardWT.createInstance(converter, pl, encSpec); quant = Quantizer.createInstance(dwt, encSpec); rois = ROIScaler.createInstance(quant, pl, encSpec); ecoder = EntropyCoder.createInstance(rois, pl, encSpec.cblks, encSpec.pss, encSpec.bms, encSpec.mqrs, encSpec.rts, encSpec.css, encSpec.sss, encSpec.lcs, encSpec.tts); using (MemoryStream stream = new MemoryStream()) { bwriter = new FileCodestreamWriter(stream, Int32.MaxValue); ralloc = PostCompRateAllocator.createInstance(ecoder, pl, rate, bwriter, encSpec); headenc = new HeaderEncoder(imgsrc, new bool[3], dwt, imgtiler, encSpec, rois, ralloc, pl); ralloc.HeaderEncoder = headenc; headenc.encodeMainHeader(); ralloc.initialize(); headenc.reset(); headenc.encodeMainHeader(); bwriter.commitBitstreamHeader(headenc); ralloc.runAndWrite(); bwriter.close(); return(stream.ToArray()); } }
internal static int ec_laplace_decode(EntropyCoder dec, uint fs, int decay) { int val = 0; uint fl; uint fm; fm = dec.decode_bin(15); fl = 0; if (fm >= fs) { val++; fl = fs; fs = ec_laplace_get_freq1(fs, decay) + LAPLACE_MINP; /* Search the decaying part of the PDF.*/ while (fs > LAPLACE_MINP && fm >= fl + 2 * fs) { fs *= 2; fl += fs; fs = (uint)(((fs - 2 * LAPLACE_MINP) * (int)decay) >> 15); fs += LAPLACE_MINP; val++; } /* Everything beyond that has probability LAPLACE_MINP. */ if (fs <= LAPLACE_MINP) { int di; di = (int)(fm - fl) >> (LAPLACE_LOG_MINP + 1); val += di; fl += (uint)(2 * di * LAPLACE_MINP); } if (fm < fl + fs) { val = -val; } else { fl += fs; } } Inlines.OpusAssert(fl < 32768); Inlines.OpusAssert(fs > 0); Inlines.OpusAssert(fl <= fm); Inlines.OpusAssert(fm < Inlines.IMIN(fl + fs, 32768)); dec.dec_update(fl, Inlines.IMIN(fl + fs, 32768), 32768); return(val); }
/** Decode pulse vector and combine the result with the pitch vector to produce * the final normalised signal in the current band. */ internal static uint alg_unquant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder dec, int gain) { int Ryy; uint collapse_mask; int[] iy = new int[N]; Inlines.OpusAssert(K > 0, "alg_unquant() needs at least one pulse"); Inlines.OpusAssert(N > 1, "alg_unquant() needs at least two dimensions"); Ryy = CWRS.decode_pulses(iy, N, K, dec); normalise_residual(iy, X, X_ptr, N, Ryy, gain); exp_rotation(X, X_ptr, N, -1, B, K, spread); collapse_mask = extract_collapse_mask(iy, N, B); return(collapse_mask); }
/// <summary> /// Entropy code the mid/side quantization indices /// </summary> /// <param name="psRangeEnc">I/O Compressor data structure</param> /// <param name="ix">I Quantization indices [ 2 ][ 3 ]</param> internal static void silk_stereo_encode_pred(EntropyCoder psRangeEnc, sbyte[][] ix) { int n; /* Entropy coding */ n = 5 * ix[0][2] + ix[1][2]; Inlines.OpusAssert(n < 25); psRangeEnc.enc_icdf(n, Tables.silk_stereo_pred_joint_iCDF, 8); for (n = 0; n < 2; n++) { Inlines.OpusAssert(ix[n][0] < 3); Inlines.OpusAssert(ix[n][1] < SilkConstants.STEREO_QUANT_SUB_STEPS); psRangeEnc.enc_icdf(ix[n][0], Tables.silk_uniform3_iCDF, 8); psRangeEnc.enc_icdf(ix[n][1], Tables.silk_uniform5_iCDF, 8); } }
internal static void ec_laplace_encode(EntropyCoder enc, ref int value, uint fs, int decay) { uint fl; int val = value; fl = 0; if (val != 0) { int s; int i; s = 0 - (val < 0 ? 1 : 0); val = (val + s) ^ s; fl = fs; fs = ec_laplace_get_freq1(fs, decay); /* Search the decaying part of the PDF.*/ for (i = 1; fs > 0 && i < val; i++) { fs *= 2; fl += fs + 2 * LAPLACE_MINP; fs = (uint)((fs * (int)decay) >> 15); } /* Everything beyond that has probability LAPLACE_MINP. */ if (fs == 0) { int di; int ndi_max; ndi_max = (int)(32768 - fl + LAPLACE_MINP - 1) >> LAPLACE_LOG_MINP; ndi_max = (ndi_max - s) >> 1; di = Inlines.IMIN(val - i, ndi_max - 1); fl += (uint)(2 * di + 1 + s) * LAPLACE_MINP; fs = Inlines.IMIN(LAPLACE_MINP, 32768 - fl); value = (i + di + s) ^ s; } else { fs += LAPLACE_MINP; fl += (uint)(fs & ~s); } Inlines.OpusAssert(fl + fs <= 32768); Inlines.OpusAssert(fs > 0); } enc.encode_bin(fl, fl + fs, 15); }
/// <summary> /// Decodes signs of excitation /// </summary> /// <param name="psRangeDec">I/O Compressor data structure</param> /// <param name="pulses">I/O pulse signal</param> /// <param name="length">I length of input</param> /// <param name="signalType">I Signal type</param> /// <param name="quantOffsetType">I Quantization offset type</param> /// <param name="sum_pulses">I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]</param> internal static void silk_decode_signs( EntropyCoder psRangeDec, short[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { int i, j, p; byte[] icdf = new byte[2]; int q_ptr; byte[] icdf_table = Tables.silk_sign_iCDF; int icdf_ptr; icdf[1] = 0; q_ptr = 0; i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); icdf_ptr = i; length = Inlines.silk_RSHIFT(length + SilkConstants.SHELL_CODEC_FRAME_LENGTH / 2, SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH); for (i = 0; i < length; i++) { p = sum_pulses[i]; if (p > 0) { icdf[0] = icdf_table[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)]; for (j = 0; j < SilkConstants.SHELL_CODEC_FRAME_LENGTH; j++) { if (pulses[q_ptr + j] > 0) { /* attach sign */ pulses[q_ptr + j] *= (short)(silk_dec_map(psRangeDec.dec_icdf(icdf, 8))); } } } q_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH; } }
/// <summary> /// /// </summary> /// <param name="p_child1">O pulse amplitude of first child subframe</param> /// <param name="child1_ptr"></param> /// <param name="p_child2">O pulse amplitude of second child subframe</param> /// <param name="p_child2_ptr"></param> /// <param name="psRangeDec">I/O Compressor data structure</param> /// <param name="p">I pulse amplitude of current subframe</param> /// <param name="shell_table">I table of shell cdfs</param> internal static void decode_split( short[] p_child1, int child1_ptr, short[] p_child2, int p_child2_ptr, EntropyCoder psRangeDec, int p, byte[] shell_table) { if (p > 0) { p_child1[child1_ptr] = (short)(psRangeDec.dec_icdf(shell_table, (Tables.silk_shell_code_table_offsets[p]), 8)); p_child2[p_child2_ptr] = (short)(p - p_child1[child1_ptr]); } else { p_child1[child1_ptr] = 0; p_child2[p_child2_ptr] = 0; } }
private void RunSignificancePassOnCoefficient(int x, int y, bool includeZeroContext) { var coefficient = CoefficientArray[GetCoefficientIndex(x, y)]; if (coefficient.Sign == 0) { var contextLabel = coefficient.ContextVector.GetSignificanceCodingContextLabel(CodeBlock.Subband.SubbandType); if ((contextLabel != 0) || includeZeroContext) { var cx = GetContext(contextLabel); if (EntropyCoder.DecodeNextBit(cx) == 1) { var sign = DecodeSign(coefficient.ContextVector, x, y); coefficient.ApplySignificance(sign, CurrentCodingPass.BitPlane); } else { coefficient.ApplySignificance(0, CurrentCodingPass.BitPlane); } } } }
/// <summary> /// Encodes signs of excitation /// </summary> /// <param name="psRangeEnc">I/O Compressor data structure</param> /// <param name="pulses">I pulse signal</param> /// <param name="length">I length of input</param> /// <param name="signalType">I Signal type</param> /// <param name="quantOffsetType">I Quantization offset type</param> /// <param name="sum_pulses">I Sum of absolute pulses per block [MAX_NB_SHELL_BLOCKS]</param> internal static void silk_encode_signs( EntropyCoder psRangeEnc, sbyte[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses) { int i, j, p; byte[] icdf = new byte[2]; int q_ptr; byte[] sign_icdf = Tables.silk_sign_iCDF; int icdf_ptr; icdf[1] = 0; q_ptr = 0; i = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1)); icdf_ptr = i; length = Inlines.silk_RSHIFT(length + (SilkConstants.SHELL_CODEC_FRAME_LENGTH / 2), SilkConstants.LOG2_SHELL_CODEC_FRAME_LENGTH); for (i = 0; i < length; i++) { p = sum_pulses[i]; if (p > 0) { icdf[0] = sign_icdf[icdf_ptr + Inlines.silk_min(p & 0x1F, 6)]; for (j = q_ptr; j < q_ptr + SilkConstants.SHELL_CODEC_FRAME_LENGTH; j++) { if (pulses[j] != 0) { psRangeEnc.enc_icdf(silk_enc_map(pulses[j]), icdf, 8); } } } q_ptr += SilkConstants.SHELL_CODEC_FRAME_LENGTH; } }
/// <summary> /// Shell encoder, operates on one shell code frame of 16 pulses /// </summary> /// <param name="psRangeEnc">I/O compressor data structure</param> /// <param name="pulses0">I data: nonnegative pulse amplitudes</param> /// <param name="pulses0_ptr"></param> internal static void silk_shell_encoder(EntropyCoder psRangeEnc, int[] pulses0, int pulses0_ptr) { int[] pulses1 = new int[8]; int[] pulses2 = new int[4]; int[] pulses3 = new int[2]; int[] pulses4 = new int[1]; /* this function operates on one shell code frame of 16 pulses */ Inlines.OpusAssert(SilkConstants.SHELL_CODEC_FRAME_LENGTH == 16); /* tree representation per pulse-subframe */ combine_pulses(pulses1, pulses0, pulses0_ptr, 8); combine_pulses(pulses2, pulses1, 4); combine_pulses(pulses3, pulses2, 2); combine_pulses(pulses4, pulses3, 1); encode_split(psRangeEnc, pulses3[0], pulses4[0], Tables.silk_shell_code_table3); encode_split(psRangeEnc, pulses2[0], pulses3[0], Tables.silk_shell_code_table2); encode_split(psRangeEnc, pulses1[0], pulses2[0], Tables.silk_shell_code_table1); encode_split(psRangeEnc, pulses0[pulses0_ptr], pulses1[0], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses0[pulses0_ptr + 2], pulses1[1], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses1[2], pulses2[1], Tables.silk_shell_code_table1); encode_split(psRangeEnc, pulses0[pulses0_ptr + 4], pulses1[2], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses0[pulses0_ptr + 6], pulses1[3], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses2[2], pulses3[1], Tables.silk_shell_code_table2); encode_split(psRangeEnc, pulses1[4], pulses2[2], Tables.silk_shell_code_table1); encode_split(psRangeEnc, pulses0[pulses0_ptr + 8], pulses1[4], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses0[pulses0_ptr + 10], pulses1[5], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses1[6], pulses2[3], Tables.silk_shell_code_table1); encode_split(psRangeEnc, pulses0[pulses0_ptr + 12], pulses1[6], Tables.silk_shell_code_table0); encode_split(psRangeEnc, pulses0[pulses0_ptr + 14], pulses1[7], Tables.silk_shell_code_table0); }
/* Shell decoder, operates on one shell code frame of 16 pulses */ internal static void silk_shell_decoder( short[] pulses0, /* O data: nonnegative pulse amplitudes */ int pulses0_ptr, EntropyCoder psRangeDec, /* I/O Compressor data structure */ int pulses4 /* I number of pulses per pulse-subframe */ ) { short[] pulses1 = new short[8]; short[] pulses2 = new short[4]; short[] pulses3 = new short[2]; /* this function operates on one shell code frame of 16 pulses */ Inlines.OpusAssert(SilkConstants.SHELL_CODEC_FRAME_LENGTH == 16); decode_split(pulses3, 0, pulses3, 1, psRangeDec, pulses4, Tables.silk_shell_code_table3); decode_split(pulses2, 0, pulses2, 1, psRangeDec, pulses3[0], Tables.silk_shell_code_table2); decode_split(pulses1, 0, pulses1, 1, psRangeDec, pulses2[0], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr, pulses0, pulses0_ptr + 1, psRangeDec, pulses1[0], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 2, pulses0, pulses0_ptr + 3, psRangeDec, pulses1[1], Tables.silk_shell_code_table0); decode_split(pulses1, 2, pulses1, 3, psRangeDec, pulses2[1], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr + 4, pulses0, pulses0_ptr + 5, psRangeDec, pulses1[2], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 6, pulses0, pulses0_ptr + 7, psRangeDec, pulses1[3], Tables.silk_shell_code_table0); decode_split(pulses2, 2, pulses2, 3, psRangeDec, pulses3[1], Tables.silk_shell_code_table2); decode_split(pulses1, 4, pulses1, 5, psRangeDec, pulses2[2], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr + 8, pulses0, pulses0_ptr + 9, psRangeDec, pulses1[4], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 10, pulses0, pulses0_ptr + 11, psRangeDec, pulses1[5], Tables.silk_shell_code_table0); decode_split(pulses1, 6, pulses1, 7, psRangeDec, pulses2[3], Tables.silk_shell_code_table1); decode_split(pulses0, pulses0_ptr + 12, pulses0, pulses0_ptr + 13, psRangeDec, pulses1[6], Tables.silk_shell_code_table0); decode_split(pulses0, pulses0_ptr + 14, pulses0, pulses0_ptr + 15, psRangeDec, pulses1[7], Tables.silk_shell_code_table0); }
internal static void unquant_fine_energy(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, EntropyCoder dec, int C) { int i, c; /* Decode finer resolution */ for (i = start; i < end; i++) { if (fine_quant[i] <= 0) { continue; } c = 0; do { int q2; int offset; q2 = (int)dec.dec_bits((uint)fine_quant[i]); offset = Inlines.SUB16((Inlines.SHR32( Inlines.SHL32(q2, CeltConstants.DB_SHIFT) + ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/, fine_quant[i])), ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/); // opus bug: unnecessary extend32 oldEBands[i + c * m.nbEBands] += offset; } while (++c < C); } }
internal static void unquant_coarse_energy(CeltMode m, int start, int end, int[] oldEBands, int intra, EntropyCoder dec, int C, int LM) { byte[] prob_model = Tables.e_prob_model[LM][intra]; int i, c; int[] prev = { 0, 0 }; int coef; int beta; int budget; int tell; if (intra != 0) { coef = 0; beta = beta_intra; } else { beta = beta_coef[LM]; coef = pred_coef[LM]; } budget = (int)dec.storage * 8; /* Decode at a fixed coarse resolution */ for (i = start; i < end; i++) { c = 0; do { int qi; int q; int tmp; /* It would be better to express this invariant as a * test on C at function entry, but that isn't enough * to make the static analyzer happy. */ Inlines.OpusAssert(c < 2); tell = dec.tell(); if (budget - tell >= 15) { int pi; pi = 2 * Inlines.IMIN(i, 20); qi = Laplace.ec_laplace_decode(dec, (uint)prob_model[pi] << 7, prob_model[pi + 1] << 6); } else if (budget - tell >= 2) { qi = dec.dec_icdf(small_energy_icdf, 2); qi = (qi >> 1) ^ -(qi & 1); } else if (budget - tell >= 1) { qi = 0 - dec.dec_bit_logp(1); } else { qi = -1; } q = (int)Inlines.SHL32(qi, CeltConstants.DB_SHIFT); // opus bug: useless extend32 oldEBands[i + c * m.nbEBands] = Inlines.MAX16((0 - ((short)(0.5 + (9.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(9.0f, CeltConstants.DB_SHIFT)*/), oldEBands[i + c * m.nbEBands]); tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldEBands[i + c * m.nbEBands]), 8) + prev[c] + Inlines.SHL32(q, 7); tmp = Inlines.MAX32(-((int)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT + 7)))) /*Inlines.QCONST32(28.0f, CeltConstants.DB_SHIFT + 7)*/, tmp); oldEBands[i + c * m.nbEBands] = (Inlines.PSHR32(tmp, 7)); prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8)); } while (++c < C); } }
internal static void quant_fine_energy(CeltMode m, int start, int end, int[][] oldEBands, int[][] error, int[] fine_quant, EntropyCoder enc, int C) { int i, c; /* Encode finer resolution */ for (i = start; i < end; i++) { int frac = (1 << fine_quant[i]); if (fine_quant[i] <= 0) { continue; } c = 0; do { int q2; int offset; /* Has to be without rounding */ q2 = (error[c][i] + ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/) >> (CeltConstants.DB_SHIFT - fine_quant[i]); if (q2 > frac - 1) { q2 = frac - 1; } if (q2 < 0) { q2 = 0; } enc.enc_bits((uint)q2, (uint)fine_quant[i]); offset = Inlines.SUB16( (Inlines.SHR32( Inlines.SHL32(q2, CeltConstants.DB_SHIFT) + ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/, fine_quant[i])), ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/); oldEBands[c][i] += offset; error[c][i] -= offset; } while (++c < C); } }
internal static void quant_coarse_energy(CeltMode m, int start, int end, int effEnd, int[][] eBands, int[][] oldEBands, uint budget, int[][] error, EntropyCoder enc, int C, int LM, int nbAvailableBytes, int force_intra, ref int delayedIntra, int two_pass, int loss_rate, int lfe) { int intra; int max_decay; int[][] oldEBands_intra; int[][] error_intra; EntropyCoder enc_start_state = new EntropyCoder(); // [porting note] stack variable uint tell; int badness1 = 0; int intra_bias; int new_distortion; intra = (force_intra != 0 || (two_pass == 0 && delayedIntra > 2 * C * (end - start) && nbAvailableBytes > (end - start) * C)) ? 1 : 0; intra_bias = (int)((budget * delayedIntra * loss_rate) / (C * 512)); new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m.nbEBands, C); tell = (uint)enc.tell(); if (tell + 3 > budget) { two_pass = intra = 0; } max_decay = ((short)(0.5 + (16.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(16.0f, CeltConstants.DB_SHIFT)*/; if (end - start > 10) { max_decay = (Inlines.MIN32(max_decay, Inlines.SHL32(nbAvailableBytes, CeltConstants.DB_SHIFT - 3))); // opus bug: useless extend32 } if (lfe != 0) { max_decay = ((short)(0.5 + (3.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(3.0f, CeltConstants.DB_SHIFT)*/; } enc_start_state.Assign(enc); oldEBands_intra = Arrays.InitTwoDimensionalArray <int>(C, m.nbEBands); error_intra = Arrays.InitTwoDimensionalArray <int>(C, m.nbEBands); Array.Copy(oldEBands[0], 0, oldEBands_intra[0], 0, m.nbEBands); if (C == 2) { Array.Copy(oldEBands[1], 0, oldEBands_intra[1], 0, m.nbEBands); } if (two_pass != 0 || intra != 0) { badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, (int)budget, (int)tell, Tables.e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe); } if (intra == 0) { int intra_buf; EntropyCoder enc_intra_state = new EntropyCoder(); // [porting note] stack variable int tell_intra; uint nstart_bytes; uint nintra_bytes; uint save_bytes; int badness2; byte[] intra_bits = null; tell_intra = (int)enc.tell_frac(); enc_intra_state.Assign(enc); nstart_bytes = enc_start_state.range_bytes(); nintra_bytes = enc_intra_state.range_bytes(); intra_buf = enc_intra_state.buf_ptr + (int)nstart_bytes; save_bytes = nintra_bytes - nstart_bytes; if (save_bytes != 0) { intra_bits = new byte[(int)save_bytes]; /* Copy bits from intra bit-stream */ Array.Copy(enc_intra_state.buf, intra_buf, intra_bits, 0, (int)save_bytes); } enc.Assign(enc_start_state); badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, (int)budget, (int)tell, Tables.e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe); if (two_pass != 0 && (badness1 < badness2 || (badness1 == badness2 && ((int)enc.tell_frac()) + intra_bias > tell_intra))) { enc.Assign(enc_intra_state); /* Copy intra bits to bit-stream */ if (intra_bits != null) { Array.Copy(intra_bits, 0, enc_intra_state.buf, intra_buf, (int)(nintra_bytes - nstart_bytes)); } Array.Copy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands); Array.Copy(error_intra[0], 0, error[0], 0, m.nbEBands); if (C == 2) { Array.Copy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands); Array.Copy(error_intra[1], 0, error[1], 0, m.nbEBands); } intra = 1; } } else { Array.Copy(oldEBands_intra[0], 0, oldEBands[0], 0, m.nbEBands); Array.Copy(error_intra[0], 0, error[0], 0, m.nbEBands); if (C == 2) { Array.Copy(oldEBands_intra[1], 0, oldEBands[1], 0, m.nbEBands); Array.Copy(error_intra[1], 0, error[1], 0, m.nbEBands); } } if (intra != 0) { delayedIntra = new_distortion; } else { delayedIntra = Inlines.ADD32(Inlines.MULT16_32_Q15(Inlines.MULT16_16_Q15(pred_coef[LM], pred_coef[LM]), delayedIntra), new_distortion); } }
internal int celt_decode_with_ec(byte[] data, int data_ptr, int len, short[] pcm, int pcm_ptr, int frame_size, EntropyCoder dec, int accum) { int c, i, N; int spread_decision; int bits; int[][] X; int[] fine_quant; int[] pulses; int[] cap; int[] offsets; int[] fine_priority; int[] tf_res; byte[] collapse_masks; int[][] out_syn = new int[2][]; int[] out_syn_ptrs = new int[2]; int[] oldBandE, oldLogE, oldLogE2, backgroundLogE; int shortBlocks; int isTransient; int intra_ener; int CC = this.channels; int LM, M; int start; int end; int effEnd; int codedBands; int alloc_trim; int postfilter_pitch; int postfilter_gain; int intensity = 0; int dual_stereo = 0; int total_bits; int balance; int tell; int dynalloc_logp; int postfilter_tapset; int anti_collapse_rsv; int anti_collapse_on = 0; int silence; int C = this.stream_channels; CeltMode mode; // porting note: pointer int nbEBands; int overlap; short[] eBands; mode = this.mode; nbEBands = mode.nbEBands; overlap = mode.overlap; eBands = mode.eBands; start = this.start; end = this.end; frame_size *= this.downsample; oldBandE = this.oldEBands; oldLogE = this.oldLogE; oldLogE2 = this.oldLogE2; backgroundLogE = this.backgroundLogE; { for (LM = 0; LM <= mode.maxLM; LM++) { if (mode.shortMdctSize << LM == frame_size) { break; } } if (LM > mode.maxLM) { return(OpusError.OPUS_BAD_ARG); } } M = 1 << LM; if (len < 0 || len > 1275 || pcm == null) { return(OpusError.OPUS_BAD_ARG); } N = M * mode.shortMdctSize; c = 0; do { out_syn[c] = this.decode_mem[c]; out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N; } while (++c < CC); effEnd = end; if (effEnd > mode.effEBands) { effEnd = mode.effEBands; } if (data == null || len <= 1) { this.celt_decode_lost(N, LM); CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum); return(frame_size / this.downsample); } if (dec == null) { // If no entropy decoder was passed into this function, we need to create // a new one here for local use only. It only exists in this function scope. dec = new EntropyCoder(); dec.dec_init(data, data_ptr, (uint)len); } if (C == 1) { for (i = 0; i < nbEBands; i++) { oldBandE[i] = Inlines.MAX16(oldBandE[i], oldBandE[nbEBands + i]); } } total_bits = len * 8; tell = dec.tell(); if (tell >= total_bits) { silence = 1; } else if (tell == 1) { silence = dec.dec_bit_logp(15); } else { silence = 0; } if (silence != 0) { /* Pretend we've read all the remaining bits */ tell = len * 8; dec.nbits_total += tell - dec.tell(); } postfilter_gain = 0; postfilter_pitch = 0; postfilter_tapset = 0; if (start == 0 && tell + 16 <= total_bits) { if (dec.dec_bit_logp(1) != 0) { int qg, octave; octave = (int)dec.dec_uint(6); postfilter_pitch = (16 << octave) + (int)dec.dec_bits(4 + (uint)octave) - 1; qg = (int)dec.dec_bits(3); if (dec.tell() + 2 <= total_bits) { postfilter_tapset = dec.dec_icdf(Tables.tapset_icdf, 2); } postfilter_gain = ((short)(0.5 + (.09375f) * (((int)1) << (15)))) /*Inlines.QCONST16(.09375f, 15)*/ * (qg + 1); } tell = dec.tell(); } if (LM > 0 && tell + 3 <= total_bits) { isTransient = dec.dec_bit_logp(3); tell = dec.tell(); } else { isTransient = 0; } if (isTransient != 0) { shortBlocks = M; } else { shortBlocks = 0; } /* Decode the global flags (first symbols in the stream) */ intra_ener = tell + 3 <= total_bits?dec.dec_bit_logp(3) : 0; /* Get band energies */ QuantizeBands.unquant_coarse_energy(mode, start, end, oldBandE, intra_ener, dec, C, LM); tf_res = new int[nbEBands]; CeltCommon.tf_decode(start, end, isTransient, tf_res, LM, dec); tell = dec.tell(); spread_decision = Spread.SPREAD_NORMAL; if (tell + 4 <= total_bits) { spread_decision = dec.dec_icdf(Tables.spread_icdf, 5); } cap = new int[nbEBands]; CeltCommon.init_caps(mode, cap, LM, C); offsets = new int[nbEBands]; dynalloc_logp = 6; total_bits <<= EntropyCoder.BITRES; tell = (int)dec.tell_frac(); for (i = start; i < end; i++) { int width, quanta; int dynalloc_loop_logp; int boost; width = C * (eBands[i + 1] - eBands[i]) << LM; /* quanta is 6 bits, but no more than 1 bit/sample * and no less than 1/8 bit/sample */ quanta = Inlines.IMIN(width << EntropyCoder.BITRES, Inlines.IMAX(6 << EntropyCoder.BITRES, width)); dynalloc_loop_logp = dynalloc_logp; boost = 0; while (tell + (dynalloc_loop_logp << EntropyCoder.BITRES) < total_bits && boost < cap[i]) { int flag; flag = dec.dec_bit_logp((uint)dynalloc_loop_logp); tell = (int)dec.tell_frac(); if (flag == 0) { break; } boost += quanta; total_bits -= quanta; dynalloc_loop_logp = 1; } offsets[i] = boost; /* Making dynalloc more likely */ if (boost > 0) { dynalloc_logp = Inlines.IMAX(2, dynalloc_logp - 1); } } fine_quant = new int[nbEBands]; alloc_trim = tell + (6 << EntropyCoder.BITRES) <= total_bits? dec.dec_icdf(Tables.trim_icdf, 7) : 5; bits = (((int)len * 8) << EntropyCoder.BITRES) - (int)dec.tell_frac() - 1; anti_collapse_rsv = isTransient != 0 && LM >= 2 && bits >= ((LM + 2) << EntropyCoder.BITRES) ? (1 << EntropyCoder.BITRES) : 0; bits -= anti_collapse_rsv; pulses = new int[nbEBands]; fine_priority = new int[nbEBands]; codedBands = Rate.compute_allocation(mode, start, end, offsets, cap, alloc_trim, ref intensity, ref dual_stereo, bits, out balance, pulses, fine_quant, fine_priority, C, LM, dec, 0, 0, 0); QuantizeBands.unquant_fine_energy(mode, start, end, oldBandE, fine_quant, dec, C); c = 0; do { Arrays.MemMoveInt(decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + overlap / 2); } while (++c < CC); /* Decode fixed codebook */ collapse_masks = new byte[C * nbEBands]; X = Arrays.InitTwoDimensionalArray <int>(C, N); /**< Interleaved normalised MDCTs */ Bands.quant_all_bands(0, mode, start, end, X[0], C == 2 ? X[1] : null, collapse_masks, null, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, len * (8 << EntropyCoder.BITRES) - anti_collapse_rsv, balance, dec, LM, codedBands, ref this.rng); if (anti_collapse_rsv > 0) { anti_collapse_on = (int)dec.dec_bits(1); } QuantizeBands.unquant_energy_finalise(mode, start, end, oldBandE, fine_quant, fine_priority, len * 8 - dec.tell(), dec, C); if (anti_collapse_on != 0) { Bands.anti_collapse(mode, X, collapse_masks, LM, C, N, start, end, oldBandE, oldLogE, oldLogE2, pulses, this.rng); } if (silence != 0) { for (i = 0; i < C * nbEBands; i++) { oldBandE[i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/; } } CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, oldBandE, start, effEnd, C, CC, isTransient, LM, this.downsample, silence); c = 0; do { this.postfilter_period = Inlines.IMAX(this.postfilter_period, CeltConstants.COMBFILTER_MINPERIOD); this.postfilter_period_old = Inlines.IMAX(this.postfilter_period_old, CeltConstants.COMBFILTER_MINPERIOD); CeltCommon.comb_filter(out_syn[c], out_syn_ptrs[c], out_syn[c], out_syn_ptrs[c], this.postfilter_period_old, this.postfilter_period, mode.shortMdctSize, this.postfilter_gain_old, this.postfilter_gain, this.postfilter_tapset_old, this.postfilter_tapset, mode.window, overlap); if (LM != 0) { CeltCommon.comb_filter( out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize), out_syn[c], out_syn_ptrs[c] + (mode.shortMdctSize), this.postfilter_period, postfilter_pitch, N - mode.shortMdctSize, this.postfilter_gain, postfilter_gain, this.postfilter_tapset, postfilter_tapset, mode.window, overlap); } } while (++c < CC); this.postfilter_period_old = this.postfilter_period; this.postfilter_gain_old = this.postfilter_gain; this.postfilter_tapset_old = this.postfilter_tapset; this.postfilter_period = postfilter_pitch; this.postfilter_gain = postfilter_gain; this.postfilter_tapset = postfilter_tapset; if (LM != 0) { this.postfilter_period_old = this.postfilter_period; this.postfilter_gain_old = this.postfilter_gain; this.postfilter_tapset_old = this.postfilter_tapset; } if (C == 1) { Array.Copy(oldBandE, 0, oldBandE, nbEBands, nbEBands); } /* In case start or end were to change */ if (isTransient == 0) { int max_background_increase; Array.Copy(oldLogE, oldLogE2, 2 * nbEBands); Array.Copy(oldBandE, oldLogE, 2 * nbEBands); /* In normal circumstances, we only allow the noise floor to increase by * up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB * increase for each update.*/ if (this.loss_count < 10) { max_background_increase = M * ((short)(0.5 + (0.001f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(0.001f, CeltConstants.DB_SHIFT)*/; } else { max_background_increase = ((short)(0.5 + (1.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(1.0f, CeltConstants.DB_SHIFT)*/; } for (i = 0; i < 2 * nbEBands; i++) { backgroundLogE[i] = Inlines.MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); } } else { for (i = 0; i < 2 * nbEBands; i++) { oldLogE[i] = Inlines.MIN16(oldLogE[i], oldBandE[i]); } } c = 0; do { for (i = 0; i < start; i++) { oldBandE[c * nbEBands + i] = 0; oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/; } for (i = end; i < nbEBands; i++) { oldBandE[c * nbEBands + i] = 0; oldLogE[c * nbEBands + i] = oldLogE2[c * nbEBands + i] = -((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/; } } while (++c < 2); this.rng = dec.rng; CeltCommon.deemphasis(out_syn, out_syn_ptrs, pcm, pcm_ptr, N, CC, this.downsample, mode.preemph, this.preemph_memD, accum); this.loss_count = 0; if (dec.tell() > 8 * len) { return(OpusError.OPUS_INTERNAL_ERROR); } if (dec.get_error() != 0) { this.error = 1; } return(frame_size / this.downsample); }
internal static int decode_pulses(int[] _y, int _n, int _k, EntropyCoder _dec) { return(cwrsi(_n, _k, _dec.dec_uint(CELT_PVQ_V(_n, _k)), _y)); }
/// <summary> /// Entropy code the mid-only flag /// </summary> /// <param name="psRangeEnc">I/O Compressor data structure</param> /// <param name="mid_only_flag"></param> internal static void silk_stereo_encode_mid_only(EntropyCoder psRangeEnc, sbyte mid_only_flag) { /* Encode flag that only mid channel is coded */ psRangeEnc.enc_icdf(mid_only_flag, Tables.silk_stereo_only_code_mid_iCDF, 8); }
internal static int compute_allocation(CeltMode m, int start, int end, int[] offsets, int[] cap, int alloc_trim, ref int intensity, ref int dual_stereo, int total, out int balance, int[] pulses, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth) { int lo, hi, len, j; int codedBands; int skip_start; int skip_rsv; int intensity_rsv; int dual_stereo_rsv; total = Inlines.IMAX(total, 0); len = m.nbEBands; skip_start = start; /* Reserve a bit to signal the end of manually skipped bands. */ skip_rsv = total >= 1 << EntropyCoder.BITRES ? 1 << EntropyCoder.BITRES : 0; total -= skip_rsv; /* Reserve bits for the intensity and dual stereo parameters. */ intensity_rsv = dual_stereo_rsv = 0; if (C == 2) { intensity_rsv = LOG2_FRAC_TABLE[end - start]; if (intensity_rsv > total) { intensity_rsv = 0; } else { total -= intensity_rsv; dual_stereo_rsv = total >= 1 << EntropyCoder.BITRES ? 1 << EntropyCoder.BITRES : 0; total -= dual_stereo_rsv; } } int[] bits1 = new int[len]; int[] bits2 = new int[len]; int[] thresh = new int[len]; int[] trim_offset = new int[len]; for (j = start; j < end; j++) { /* Below this threshold, we're sure not to allocate any PVQ bits */ thresh[j] = Inlines.IMAX((C) << EntropyCoder.BITRES, (3 * (m.eBands[j + 1] - m.eBands[j]) << LM << EntropyCoder.BITRES) >> 4); /* Tilt of the allocation curve */ trim_offset[j] = C * (m.eBands[j + 1] - m.eBands[j]) * (alloc_trim - 5 - LM) * (end - j - 1) * (1 << (LM + EntropyCoder.BITRES)) >> 6; /* Giving less resolution to single-coefficient bands because they get * more benefit from having one coarse value per coefficient*/ if ((m.eBands[j + 1] - m.eBands[j]) << LM == 1) { trim_offset[j] -= C << EntropyCoder.BITRES; } } lo = 1; hi = m.nbAllocVectors - 1; do { int done = 0; int psum = 0; int mid = (lo + hi) >> 1; for (j = end; j-- > start;) { int bitsj; int N = m.eBands[j + 1] - m.eBands[j]; bitsj = C * N * m.allocVectors[mid * len + j] << LM >> 2; if (bitsj > 0) { bitsj = Inlines.IMAX(0, bitsj + trim_offset[j]); } bitsj += offsets[j]; if (bitsj >= thresh[j] || done != 0) { done = 1; /* Don't allocate more than we can actually use */ psum += Inlines.IMIN(bitsj, cap[j]); } else { if (bitsj >= C << EntropyCoder.BITRES) { psum += C << EntropyCoder.BITRES; } } } if (psum > total) { hi = mid - 1; } else { lo = mid + 1; } /*printf ("lo = %d, hi = %d\n", lo, hi);*/ } while (lo <= hi); hi = lo--; /*printf ("interp between %d and %d\n", lo, hi);*/ for (j = start; j < end; j++) { int bits1j, bits2j; int N = m.eBands[j + 1] - m.eBands[j]; bits1j = C * N * m.allocVectors[lo * len + j] << LM >> 2; bits2j = hi >= m.nbAllocVectors ? cap[j] : C * N * m.allocVectors[hi * len + j] << LM >> 2; if (bits1j > 0) { bits1j = Inlines.IMAX(0, bits1j + trim_offset[j]); } if (bits2j > 0) { bits2j = Inlines.IMAX(0, bits2j + trim_offset[j]); } if (lo > 0) { bits1j += offsets[j]; } bits2j += offsets[j]; if (offsets[j] > 0) { skip_start = j; } bits2j = Inlines.IMAX(0, bits2j - bits1j); bits1[j] = bits1j; bits2[j] = bits2j; } codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, total, out balance, skip_rsv, ref intensity, intensity_rsv, ref dual_stereo, dual_stereo_rsv, pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth); return(codedBands); }
internal static int interp_bits2pulses(CeltMode m, int start, int end, int skip_start, int[] bits1, int[] bits2, int[] thresh, int[] cap, int total, out int _balance, int skip_rsv, ref int intensity, int intensity_rsv, ref int dual_stereo, int dual_stereo_rsv, int[] bits, int[] ebits, int[] fine_priority, int C, int LM, EntropyCoder ec, int encode, int prev, int signalBandwidth) { int psum; int lo, hi; int i, j; int logM; int stereo; int codedBands = -1; int alloc_floor; int left, percoeff; int done; int balance; alloc_floor = C << EntropyCoder.BITRES; stereo = C > 1 ? 1 : 0; logM = LM << EntropyCoder.BITRES; lo = 0; hi = 1 << ALLOC_STEPS; for (i = 0; i < ALLOC_STEPS; i++) { int mid = (lo + hi) >> 1; psum = 0; done = 0; for (j = end; j-- > start;) { int tmp = bits1[j] + (mid * (int)bits2[j] >> ALLOC_STEPS); if (tmp >= thresh[j] || done != 0) { done = 1; /* Don't allocate more than we can actually use */ psum += Inlines.IMIN(tmp, cap[j]); } else { if (tmp >= alloc_floor) { psum += alloc_floor; } } } if (psum > total) { hi = mid; } else { lo = mid; } } psum = 0; /*printf ("interp bisection gave %d\n", lo);*/ done = 0; for (j = end; j-- > start;) { int tmp = bits1[j] + (lo * bits2[j] >> ALLOC_STEPS); if (tmp < thresh[j] && done == 0) { if (tmp >= alloc_floor) { tmp = alloc_floor; } else { tmp = 0; } } else { done = 1; } /* Don't allocate more than we can actually use */ tmp = Inlines.IMIN(tmp, cap[j]); bits[j] = tmp; psum += tmp; } /* Decide which bands to skip, working backwards from the end. */ for (codedBands = end; ; codedBands--) { int band_width; int band_bits; int rem; j = codedBands - 1; /* Never skip the first band, nor a band that has been boosted by * dynalloc. * In the first case, we'd be coding a bit to signal we're going to waste * all the other bits. * In the second case, we'd be coding a bit to redistribute all the bits * we just signaled should be cocentrated in this band. */ if (j <= skip_start) { /* Give the bit we reserved to end skipping back. */ total += skip_rsv; break; } /*Figure out how many left-over bits we would be adding to this band. * This can include bits we've stolen back from higher, skipped bands.*/ left = total - psum; percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]); left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff; rem = Inlines.IMAX(left - (m.eBands[j] - m.eBands[start]), 0); band_width = m.eBands[codedBands] - m.eBands[j]; band_bits = (int)(bits[j] + percoeff * band_width + rem); /*Only code a skip decision if we're above the threshold for this band. * Otherwise it is force-skipped. * This ensures that we have enough bits to code the skip flag.*/ if (band_bits >= Inlines.IMAX(thresh[j], alloc_floor + (1 << EntropyCoder.BITRES))) { if (encode != 0) { /*This if() block is the only part of the allocation function that * is not a mandatory part of the bitstream: any bands we choose to * skip here must be explicitly signaled.*/ /*Choose a threshold with some hysteresis to keep bands from * fluctuating in and out.*/ #if FUZZING if ((new Random().Next() & 0x1) == 0) #else if (codedBands <= start + 2 || (band_bits > ((j < prev ? 7 : 9) * band_width << LM << EntropyCoder.BITRES) >> 4 && j <= signalBandwidth)) #endif { ec.enc_bit_logp(1, 1); break; } ec.enc_bit_logp(0, 1); } else if (ec.dec_bit_logp(1) != 0) { break; } /*We used a bit to skip this band.*/ psum += 1 << EntropyCoder.BITRES; band_bits -= 1 << EntropyCoder.BITRES; } /*Reclaim the bits originally allocated to this band.*/ psum -= bits[j] + intensity_rsv; if (intensity_rsv > 0) { intensity_rsv = LOG2_FRAC_TABLE[j - start]; } psum += intensity_rsv; if (band_bits >= alloc_floor) { /*If we have enough for a fine energy bit per channel, use it.*/ psum += alloc_floor; bits[j] = alloc_floor; } else { /*Otherwise this band gets nothing at all.*/ bits[j] = 0; } } Inlines.OpusAssert(codedBands > start); /* Code the intensity and dual stereo parameters. */ if (intensity_rsv > 0) { if (encode != 0) { intensity = Inlines.IMIN(intensity, codedBands); ec.enc_uint((uint)(intensity - start), (uint)(codedBands + 1 - start)); } else { intensity = start + (int)ec.dec_uint((uint)(codedBands + 1 - start)); } } else { intensity = 0; } if (intensity <= start) { total += dual_stereo_rsv; dual_stereo_rsv = 0; } if (dual_stereo_rsv > 0) { if (encode != 0) { ec.enc_bit_logp(dual_stereo, 1); } else { dual_stereo = ec.dec_bit_logp(1); } } else { dual_stereo = 0; } /* Allocate the remaining bits */ left = total - psum; percoeff = Inlines.celt_udiv(left, m.eBands[codedBands] - m.eBands[start]); left -= (m.eBands[codedBands] - m.eBands[start]) * percoeff; for (j = start; j < codedBands; j++) { bits[j] += ((int)percoeff * (m.eBands[j + 1] - m.eBands[j])); } for (j = start; j < codedBands; j++) { int tmp = (int)Inlines.IMIN(left, m.eBands[j + 1] - m.eBands[j]); bits[j] += tmp; left -= tmp; } /*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/ balance = 0; for (j = start; j < codedBands; j++) { int N0, N, den; int offset; int NClogN; int excess, bit; Inlines.OpusAssert(bits[j] >= 0); N0 = m.eBands[j + 1] - m.eBands[j]; N = N0 << LM; bit = (int)bits[j] + balance; if (N > 1) { excess = Inlines.MAX32(bit - cap[j], 0); bits[j] = bit - excess; /* Compensate for the extra DoF in stereo */ den = (C * N + ((C == 2 && N > 2 && (dual_stereo == 0) && j < intensity) ? 1 : 0)); NClogN = den * (m.logN[j] + logM); /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET * compared to their "fair share" of total/N */ offset = (NClogN >> 1) - den * CeltConstants.FINE_OFFSET; /* N=2 is the only point that doesn't match the curve */ if (N == 2) { offset += den << EntropyCoder.BITRES >> 2; } /* Changing the offset for allocating the second and third * fine energy bit */ if (bits[j] + offset < den * 2 << EntropyCoder.BITRES) { offset += NClogN >> 2; } else if (bits[j] + offset < den * 3 << EntropyCoder.BITRES) { offset += NClogN >> 3; } /* Divide with rounding */ ebits[j] = Inlines.IMAX(0, (bits[j] + offset + (den << (EntropyCoder.BITRES - 1)))); ebits[j] = Inlines.celt_udiv(ebits[j], den) >> EntropyCoder.BITRES; /* Make sure not to bust */ if (C * ebits[j] > (bits[j] >> EntropyCoder.BITRES)) { ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES; } /* More than that is useless because that's about as far as PVQ can go */ ebits[j] = Inlines.IMIN(ebits[j], CeltConstants.MAX_FINE_BITS); /* If we rounded down or capped this band, make it a candidate for the * final fine energy pass */ fine_priority[j] = (ebits[j] * (den << EntropyCoder.BITRES) >= bits[j] + offset) ? 1 : 0; /* Remove the allocated fine bits; the rest are assigned to PVQ */ bits[j] -= C * ebits[j] << EntropyCoder.BITRES; } else { /* For N=1, all bits go to fine energy except for a single sign bit */ excess = Inlines.MAX32(0, bit - (C << EntropyCoder.BITRES)); bits[j] = bit - excess; ebits[j] = 0; fine_priority[j] = 1; } /* Fine energy can't take advantage of the re-balancing in * quant_all_bands(). * Instead, do the re-balancing here.*/ if (excess > 0) { int extra_fine; int extra_bits; extra_fine = Inlines.IMIN(excess >> (stereo + EntropyCoder.BITRES), CeltConstants.MAX_FINE_BITS - ebits[j]); ebits[j] += extra_fine; extra_bits = extra_fine * C << EntropyCoder.BITRES; fine_priority[j] = (extra_bits >= excess - balance) ? 1 : 0; excess -= extra_bits; } balance = excess; Inlines.OpusAssert(bits[j] >= 0); Inlines.OpusAssert(ebits[j] >= 0); } /* Save any remaining bits over the cap for the rebalancing in * quant_all_bands(). */ _balance = balance; /* The skipped bands use all their bits for fine energy. */ for (; j < end; j++) { ebits[j] = bits[j] >> stereo >> EntropyCoder.BITRES; Inlines.OpusAssert(C * ebits[j] << EntropyCoder.BITRES == bits[j]); bits[j] = 0; fine_priority[j] = (ebits[j] < 1) ? 1 : 0; } return(codedBands); }
/// <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); }
internal static void unquant_energy_finalise(CeltMode m, int start, int end, int[] oldEBands, int[] fine_quant, int[] fine_priority, int bits_left, EntropyCoder dec, int C) { int i, prio, c; /* Use up the remaining bits */ for (prio = 0; prio < 2; prio++) { for (i = start; i < end && bits_left >= C; i++) { if (fine_quant[i] >= CeltConstants.MAX_FINE_BITS || fine_priority[i] != prio) { continue; } c = 0; do { int q2; int offset; q2 = (int)dec.dec_bits(1); offset = Inlines.SHR16((Inlines.SHL16((q2), CeltConstants.DB_SHIFT) - ((short)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(.5f, CeltConstants.DB_SHIFT)*/), fine_quant[i] + 1); oldEBands[i + c * m.nbEBands] += offset; bits_left--; } while (++c < C); } } }
internal static int quant_coarse_energy_impl(CeltMode m, int start, int end, int[][] eBands, int[][] oldEBands, int budget, int tell, byte[] prob_model, int[][] error, EntropyCoder enc, int C, int LM, int intra, int max_decay, int lfe) { int i, c; int badness = 0; int[] prev = { 0, 0 }; int coef; int beta; if (tell + 3 <= budget) { enc.enc_bit_logp(intra, 3); } if (intra != 0) { coef = 0; beta = beta_intra; } else { beta = beta_coef[LM]; coef = pred_coef[LM]; } /* Encode at a fixed coarse resolution */ for (i = start; i < end; i++) { c = 0; do { int bits_left; int qi, qi0; int q; int x; int f, tmp; int oldE; int decay_bound; x = eBands[c][i]; oldE = Inlines.MAX16(-((short)(0.5 + (9.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(9.0f, CeltConstants.DB_SHIFT)*/, oldEBands[c][i]); f = Inlines.SHL32(Inlines.EXTEND32(x), 7) - Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) - prev[c]; /* Rounding to nearest integer here is really important! */ qi = (f + ((int)(0.5 + (.5f) * (((int)1) << (CeltConstants.DB_SHIFT + 7)))) /*Inlines.QCONST32(.5f, CeltConstants.DB_SHIFT + 7)*/) >> (CeltConstants.DB_SHIFT + 7); decay_bound = Inlines.EXTRACT16(Inlines.MAX32(-((short)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(28.0f, CeltConstants.DB_SHIFT)*/, Inlines.SUB32((int)oldEBands[c][i], max_decay))); /* Prevent the energy from going down too quickly (e.g. for bands * that have just one bin) */ if (qi < 0 && x < decay_bound) { qi += (int)Inlines.SHR16(Inlines.SUB16(decay_bound, x), CeltConstants.DB_SHIFT); if (qi > 0) { qi = 0; } } qi0 = qi; /* If we don't have enough bits to encode all the energy, just assume * something safe. */ tell = enc.tell(); bits_left = budget - tell - 3 * C * (end - i); if (i != start && bits_left < 30) { if (bits_left < 24) { qi = Inlines.IMIN(1, qi); } if (bits_left < 16) { qi = Inlines.IMAX(-1, qi); } } if (lfe != 0 && i >= 2) { qi = Inlines.IMIN(qi, 0); } if (budget - tell >= 15) { int pi; pi = 2 * Inlines.IMIN(i, 20); Laplace.ec_laplace_encode(enc, ref qi, (((uint)prob_model[pi]) << 7), ((int)prob_model[pi + 1]) << 6); } else if (budget - tell >= 2) { qi = Inlines.IMAX(-1, Inlines.IMIN(qi, 1)); enc.enc_icdf(2 * qi ^ (0 - (qi < 0 ? 1 : 0)), small_energy_icdf, 2); } else if (budget - tell >= 1) { qi = Inlines.IMIN(0, qi); enc.enc_bit_logp(-qi, 1); } else { qi = -1; } error[c][i] = (Inlines.PSHR32(f, 7) - Inlines.SHL16((qi), CeltConstants.DB_SHIFT)); badness += Inlines.abs(qi0 - qi); q = (int)Inlines.SHL32(qi, CeltConstants.DB_SHIFT); // opus bug: useless extend32 tmp = Inlines.PSHR32(Inlines.MULT16_16(coef, oldE), 8) + prev[c] + Inlines.SHL32(q, 7); tmp = Inlines.MAX32(-((int)(0.5 + (28.0f) * (((int)1) << (CeltConstants.DB_SHIFT + 7)))) /*Inlines.QCONST32(28.0f, CeltConstants.DB_SHIFT + 7)*/, tmp); oldEBands[c][i] = (Inlines.PSHR32(tmp, 7)); prev[c] = prev[c] + Inlines.SHL32(q, 7) - Inlines.MULT16_16(beta, Inlines.PSHR32(q, 8)); } while (++c < C); } return(lfe != 0 ? 0 : badness); }
internal static uint alg_quant(int[] X, int X_ptr, int N, int K, int spread, int B, EntropyCoder enc ) { int[] y = new int[N]; int[] iy = new int[N]; int[] signx = new int[N]; int i, j; int s; int pulsesLeft; int sum; int xy; int yy; uint collapse_mask; Inlines.OpusAssert(K > 0, "alg_quant() needs at least one pulse"); Inlines.OpusAssert(N > 1, "alg_quant() needs at least two dimensions"); exp_rotation(X, X_ptr, N, 1, B, K, spread); /* Get rid of the sign */ sum = 0; j = 0; do { int xpj = X_ptr + j; /* OPT: Make sure the following two lines result in conditional moves * rather than branches. */ signx[j] = X[xpj] > 0 ? 1 : -1; X[xpj] = Inlines.ABS16(X[xpj]); iy[j] = 0; y[j] = 0; } while (++j < N); xy = yy = 0; pulsesLeft = K; /* Do a pre-search by projecting on the pyramid */ if (K > (N >> 1)) { int rcp; j = 0; do { sum += X[X_ptr + j]; } while (++j < N); /* If X is too small, just replace it with a pulse at 0 */ /* Prevents infinities and NaNs from causing too many pulses * to be allocated. 64 is an approximation of infinity here. */ if (sum <= K) { X[X_ptr] = ((short)(0.5 + (1.0f) * (((int)1) << (14)))) /*Inlines.QCONST16(1.0f, 14)*/; j = X_ptr + 1; do { X[j] = 0; } while (++j < N + X_ptr); sum = ((short)(0.5 + (1.0f) * (((int)1) << (14)))) /*Inlines.QCONST16(1.0f, 14)*/; } rcp = Inlines.EXTRACT16(Inlines.MULT16_32_Q16((K - 1), Inlines.celt_rcp(sum))); j = 0; do { /* It's really important to round *towards zero* here */ iy[j] = Inlines.MULT16_16_Q15(X[X_ptr + j], rcp); y[j] = (int)iy[j]; yy = (Inlines.MAC16_16(yy, y[j], y[j])); xy = Inlines.MAC16_16(xy, X[X_ptr + j], y[j]); y[j] *= 2; pulsesLeft -= iy[j]; } while (++j < N); } Inlines.OpusAssert(pulsesLeft >= 1, "Allocated too many pulses in the quick pass"); /* This should never happen, but just in case it does (e.g. on silence) * we fill the first bin with pulses. */ if (pulsesLeft > N + 3) { int tmp = (int)pulsesLeft; yy = (Inlines.MAC16_16(yy, tmp, tmp)); yy = (Inlines.MAC16_16(yy, tmp, y[0])); iy[0] += pulsesLeft; pulsesLeft = 0; } s = 1; for (i = 0; i < pulsesLeft; i++) { int best_id; int best_num = 0 - CeltConstants.VERY_LARGE16; int best_den = 0; int rshift = 1 + Inlines.celt_ilog2(K - pulsesLeft + i + 1); best_id = 0; /* The squared magnitude term gets added anyway, so we might as well * add it outside the loop */ yy = Inlines.ADD16(yy, 1); // opus bug - was add32 j = 0; do { int Rxy, Ryy; /* Temporary sums of the new pulse(s) */ Rxy = Inlines.EXTRACT16(Inlines.SHR32(Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + j])), rshift)); /* We're multiplying y[j] by two so we don't have to do it here */ Ryy = Inlines.ADD16(yy, y[j]); /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that * Rxy is positive because the sign is pre-computed) */ Rxy = Inlines.MULT16_16_Q15(Rxy, Rxy); /* The idea is to check for num/den >= best_num/best_den, but that way * we can do it without any division */ /* OPT: Make sure to use conditional moves here */ if (Inlines.MULT16_16(best_den, Rxy) > Inlines.MULT16_16(Ryy, best_num)) { best_den = Ryy; best_num = Rxy; best_id = j; } } while (++j < N); /* Updating the sums of the new pulse(s) */ xy = Inlines.ADD32(xy, Inlines.EXTEND32(X[X_ptr + best_id])); /* We're multiplying y[j] by two so we don't have to do it here */ yy = Inlines.ADD16(yy, y[best_id]); /* Only now that we've made the final choice, update y/iy */ /* Multiplying y[j] by 2 so we don't have to do it everywhere else */ y[best_id] = (y[best_id] + (2 * s)); iy[best_id]++; } /* Put the original sign back */ j = 0; do { X[X_ptr + j] = (Inlines.MULT16_16(signx[j], X[X_ptr + j])); /* OPT: Make sure your compiler uses a conditional move here rather than * a branch. */ iy[j] = signx[j] < 0 ? -iy[j] : iy[j]; } while (++j < N); CWRS.encode_pulses(iy, N, K, enc); collapse_mask = extract_collapse_mask(iy, N, B); return(collapse_mask); }
/// <summary> /// Encode frame with Silk /// Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what /// encControl.payloadSize_ms is set to /// </summary> /// <param name="psEnc">I/O State</param> /// <param name="encControl">I Control status</param> /// <param name="samplesIn">I Speech sample input vector</param> /// <param name="nSamplesIn">I Number of samples in input vector</param> /// <param name="psRangeEnc">I/O Compressor data structure</param> /// <param name="nBytesOut">I/O Number of bytes in payload (input: Max bytes)</param> /// <param name="prefillFlag">I Flag to indicate prefilling buffers no coding</param> /// <returns>error code</returns> internal static int silk_Encode( SilkEncoder psEnc, EncControlState encControl, short[] samplesIn, int nSamplesIn, EntropyCoder psRangeEnc, BoxedValueInt nBytesOut, int prefillFlag) { int ret = SilkError.SILK_NO_ERROR; int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0; int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms; int nSamplesFromInput = 0, nSamplesFromInputMax; int speech_act_thr_for_switch_Q8; int TargetRate_bps, channelRate_bps, LBRR_symbol, sum; int[] MStargetRates_bps = new int[2]; short[] buf; int transition, curr_block, tot_blocks; nBytesOut.Val = 0; if (encControl.reducedDependency != 0) { psEnc.state_Fxx[0].first_frame_after_reset = 1; psEnc.state_Fxx[1].first_frame_after_reset = 1; } psEnc.state_Fxx[0].nFramesEncoded = psEnc.state_Fxx[1].nFramesEncoded = 0; /* Check values in encoder control structure */ ret += encControl.check_control_input(); if (ret != SilkError.SILK_NO_ERROR) { Inlines.OpusAssert(false); return(ret); } encControl.switchReady = 0; if (encControl.nChannelsInternal > psEnc.nChannelsInternal) { /* Mono . Stereo transition: init state of second channel and stereo state */ ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[1]); Arrays.MemSetShort(psEnc.sStereo.pred_prev_Q13, 0, 2); Arrays.MemSetShort(psEnc.sStereo.sSide, 0, 2); psEnc.sStereo.mid_side_amp_Q0[0] = 0; psEnc.sStereo.mid_side_amp_Q0[1] = 1; psEnc.sStereo.mid_side_amp_Q0[2] = 0; psEnc.sStereo.mid_side_amp_Q0[3] = 1; psEnc.sStereo.width_prev_Q14 = 0; psEnc.sStereo.smth_width_Q14 = (short)(((int)((1.0f) * ((long)1 << (14)) + 0.5)) /*Inlines.SILK_CONST(1.0f, 14)*/); if (psEnc.nChannelsAPI == 2) { psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state); Array.Copy(psEnc.state_Fxx[0].In_HP_State, psEnc.state_Fxx[1].In_HP_State, 2); } } transition = ((encControl.payloadSize_ms != psEnc.state_Fxx[0].PacketSize_ms) || (psEnc.nChannelsInternal != encControl.nChannelsInternal)) ? 1 : 0; psEnc.nChannelsAPI = encControl.nChannelsAPI; psEnc.nChannelsInternal = encControl.nChannelsInternal; nBlocksOf10ms = Inlines.silk_DIV32(100 * nSamplesIn, encControl.API_sampleRate); tot_blocks = (nBlocksOf10ms > 1) ? nBlocksOf10ms >> 1 : 1; curr_block = 0; if (prefillFlag != 0) { /* Only accept input length of 10 ms */ if (nBlocksOf10ms != 1) { Inlines.OpusAssert(false); return(SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES); } /* Reset Encoder */ for (n = 0; n < encControl.nChannelsInternal; n++) { ret += SilkEncoder.silk_init_encoder(psEnc.state_Fxx[n]); Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR); } tmp_payloadSize_ms = encControl.payloadSize_ms; encControl.payloadSize_ms = 10; tmp_complexity = encControl.complexity; encControl.complexity = 0; for (n = 0; n < encControl.nChannelsInternal; n++) { psEnc.state_Fxx[n].controlled_since_last_payload = 0; psEnc.state_Fxx[n].prefillFlag = 1; } } else { /* Only accept input lengths that are a multiple of 10 ms */ if (nBlocksOf10ms * encControl.API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0) { Inlines.OpusAssert(false); return(SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES); } /* Make sure no more than one packet can be produced */ if (1000 * (int)nSamplesIn > encControl.payloadSize_ms * encControl.API_sampleRate) { Inlines.OpusAssert(false); return(SilkError.SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES); } } TargetRate_bps = Inlines.silk_RSHIFT32(encControl.bitRate, encControl.nChannelsInternal - 1); for (n = 0; n < encControl.nChannelsInternal; n++) { /* Force the side channel to the same rate as the mid */ int force_fs_kHz = (n == 1) ? psEnc.state_Fxx[0].fs_kHz : 0; ret += psEnc.state_Fxx[n].silk_control_encoder(encControl, TargetRate_bps, psEnc.allowBandwidthSwitch, n, force_fs_kHz); if (ret != SilkError.SILK_NO_ERROR) { Inlines.OpusAssert(false); return(ret); } if (psEnc.state_Fxx[n].first_frame_after_reset != 0 || transition != 0) { for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; i++) { psEnc.state_Fxx[n].LBRR_flags[i] = 0; } } psEnc.state_Fxx[n].inDTX = psEnc.state_Fxx[n].useDTX; } Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[0].fs_kHz == psEnc.state_Fxx[1].fs_kHz); /* Input buffering/resampling and encoding */ nSamplesToBufferMax = 10 * nBlocksOf10ms * psEnc.state_Fxx[0].fs_kHz; nSamplesFromInputMax = Inlines.silk_DIV32_16(nSamplesToBufferMax * psEnc.state_Fxx[0].API_fs_Hz, (short)(psEnc.state_Fxx[0].fs_kHz * 1000)); buf = new short[nSamplesFromInputMax]; int samplesIn_ptr = 0; while (true) { nSamplesToBuffer = psEnc.state_Fxx[0].frame_length - psEnc.state_Fxx[0].inputBufIx; nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, nSamplesToBufferMax); nSamplesFromInput = Inlines.silk_DIV32_16(nSamplesToBuffer * psEnc.state_Fxx[0].API_fs_Hz, psEnc.state_Fxx[0].fs_kHz * 1000); /* Resample and write to buffer */ if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 2) { int id = psEnc.state_Fxx[0].nFramesEncoded; for (n = 0; n < nSamplesFromInput; n++) { buf[n] = samplesIn[samplesIn_ptr + (2 * n)]; } /* Making sure to start both resamplers from the same state when switching from mono to stereo */ if (psEnc.nPrevChannelsInternal == 1 && id == 0) { //silk_memcpy(&psEnc.state_Fxx[1].resampler_state, &psEnc.state_Fxx[0].resampler_state, sizeof(psEnc.state_Fxx[1].resampler_state)); psEnc.state_Fxx[1].resampler_state.Assign(psEnc.state_Fxx[0].resampler_state); } ret += Resampler.silk_resampler( psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, buf, 0, nSamplesFromInput); psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer; nSamplesToBuffer = psEnc.state_Fxx[1].frame_length - psEnc.state_Fxx[1].inputBufIx; nSamplesToBuffer = Inlines.silk_min(nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc.state_Fxx[1].fs_kHz); for (n = 0; n < nSamplesFromInput; n++) { buf[n] = samplesIn[samplesIn_ptr + (2 * n) + 1]; } ret += Resampler.silk_resampler( psEnc.state_Fxx[1].resampler_state, psEnc.state_Fxx[1].inputBuf, psEnc.state_Fxx[1].inputBufIx + 2, buf, 0, nSamplesFromInput); psEnc.state_Fxx[1].inputBufIx += nSamplesToBuffer; } else if (encControl.nChannelsAPI == 2 && encControl.nChannelsInternal == 1) { /* Combine left and right channels before resampling */ for (n = 0; n < nSamplesFromInput; n++) { sum = samplesIn[samplesIn_ptr + (2 * n)] + samplesIn[samplesIn_ptr + (2 * n) + 1]; buf[n] = (short)Inlines.silk_RSHIFT_ROUND(sum, 1); } ret += Resampler.silk_resampler( psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, buf, 0, nSamplesFromInput); /* On the first mono frame, average the results for the two resampler states */ if (psEnc.nPrevChannelsInternal == 2 && psEnc.state_Fxx[0].nFramesEncoded == 0) { ret += Resampler.silk_resampler( psEnc.state_Fxx[1].resampler_state, psEnc.state_Fxx[1].inputBuf, psEnc.state_Fxx[1].inputBufIx + 2, buf, 0, nSamplesFromInput); for (n = 0; n < psEnc.state_Fxx[0].frame_length; n++) { psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2] = (short)(Inlines.silk_RSHIFT(psEnc.state_Fxx[0].inputBuf[psEnc.state_Fxx[0].inputBufIx + n + 2] + psEnc.state_Fxx[1].inputBuf[psEnc.state_Fxx[1].inputBufIx + n + 2], 1)); } } psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer; } else { Inlines.OpusAssert(encControl.nChannelsAPI == 1 && encControl.nChannelsInternal == 1); Array.Copy(samplesIn, samplesIn_ptr, buf, 0, nSamplesFromInput); ret += Resampler.silk_resampler( psEnc.state_Fxx[0].resampler_state, psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].inputBufIx + 2, buf, 0, nSamplesFromInput); psEnc.state_Fxx[0].inputBufIx += nSamplesToBuffer; } samplesIn_ptr += (nSamplesFromInput * encControl.nChannelsAPI); nSamplesIn -= nSamplesFromInput; /* Default */ psEnc.allowBandwidthSwitch = 0; /* Silk encoder */ if (psEnc.state_Fxx[0].inputBufIx >= psEnc.state_Fxx[0].frame_length) { /* Enough data in input buffer, so encode */ Inlines.OpusAssert(psEnc.state_Fxx[0].inputBufIx == psEnc.state_Fxx[0].frame_length); Inlines.OpusAssert(encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inputBufIx == psEnc.state_Fxx[1].frame_length); /* Deal with LBRR data */ if (psEnc.state_Fxx[0].nFramesEncoded == 0 && prefillFlag == 0) { /* Create space at start of payload for VAD and FEC flags */ byte[] iCDF = { 0, 0 }; iCDF[0] = (byte)(256 - Inlines.silk_RSHIFT(256, (psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal)); psRangeEnc.enc_icdf(0, iCDF, 8); /* Encode any LBRR data from previous packet */ /* Encode LBRR flags */ for (n = 0; n < encControl.nChannelsInternal; n++) { LBRR_symbol = 0; for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; i++) { LBRR_symbol |= Inlines.silk_LSHIFT(psEnc.state_Fxx[n].LBRR_flags[i], i); } psEnc.state_Fxx[n].LBRR_flag = (sbyte)(LBRR_symbol > 0 ? 1 : 0); if (LBRR_symbol != 0 && psEnc.state_Fxx[n].nFramesPerPacket > 1) { psRangeEnc.enc_icdf(LBRR_symbol - 1, Tables.silk_LBRR_flags_iCDF_ptr[psEnc.state_Fxx[n].nFramesPerPacket - 2], 8); } } /* Code LBRR indices and excitation signals */ for (i = 0; i < psEnc.state_Fxx[0].nFramesPerPacket; i++) { for (n = 0; n < encControl.nChannelsInternal; n++) { if (psEnc.state_Fxx[n].LBRR_flags[i] != 0) { int condCoding; if (encControl.nChannelsInternal == 2 && n == 0) { Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[i]); /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ if (psEnc.state_Fxx[1].LBRR_flags[i] == 0) { Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[i]); } } /* Use conditional coding if previous frame available */ if (i > 0 && psEnc.state_Fxx[n].LBRR_flags[i - 1] != 0) { condCoding = SilkConstants.CODE_CONDITIONALLY; } else { condCoding = SilkConstants.CODE_INDEPENDENTLY; } EncodeIndices.silk_encode_indices(psEnc.state_Fxx[n], psRangeEnc, i, 1, condCoding); EncodePulses.silk_encode_pulses(psRangeEnc, psEnc.state_Fxx[n].indices_LBRR[i].signalType, psEnc.state_Fxx[n].indices_LBRR[i].quantOffsetType, psEnc.state_Fxx[n].pulses_LBRR[i], psEnc.state_Fxx[n].frame_length); } } } /* Reset LBRR flags */ for (n = 0; n < encControl.nChannelsInternal; n++) { Arrays.MemSetInt(psEnc.state_Fxx[n].LBRR_flags, 0, SilkConstants.MAX_FRAMES_PER_PACKET); } psEnc.nBitsUsedLBRR = psRangeEnc.tell(); } HPVariableCutoff.silk_HP_variable_cutoff(psEnc.state_Fxx); /* Total target bits for packet */ nBits = Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000); /* Subtract bits used for LBRR */ if (prefillFlag == 0) { nBits -= psEnc.nBitsUsedLBRR; } /* Divide by number of uncoded frames left in packet */ nBits = Inlines.silk_DIV32_16(nBits, psEnc.state_Fxx[0].nFramesPerPacket); /* Convert to bits/second */ if (encControl.payloadSize_ms == 10) { TargetRate_bps = Inlines.silk_SMULBB(nBits, 100); } else { TargetRate_bps = Inlines.silk_SMULBB(nBits, 50); } /* Subtract fraction of bits in excess of target in previous frames and packets */ TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(psEnc.nBitsExceeded, 1000), TuningParameters.BITRESERVOIR_DECAY_TIME_MS); if (prefillFlag == 0 && psEnc.state_Fxx[0].nFramesEncoded > 0) { /* Compare actual vs target bits so far in this packet */ int bitsBalance = psRangeEnc.tell() - psEnc.nBitsUsedLBRR - nBits * psEnc.state_Fxx[0].nFramesEncoded; TargetRate_bps -= Inlines.silk_DIV32_16(Inlines.silk_MUL(bitsBalance, 1000), TuningParameters.BITRESERVOIR_DECAY_TIME_MS); } /* Never exceed input bitrate */ TargetRate_bps = Inlines.silk_LIMIT(TargetRate_bps, encControl.bitRate, 5000); /* Convert Left/Right to Mid/Side */ if (encControl.nChannelsInternal == 2) { BoxedValueSbyte midOnlyFlagBoxed = new BoxedValueSbyte(psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]); Stereo.silk_stereo_LR_to_MS(psEnc.sStereo, psEnc.state_Fxx[0].inputBuf, 2, psEnc.state_Fxx[1].inputBuf, 2, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded], midOnlyFlagBoxed, MStargetRates_bps, TargetRate_bps, psEnc.state_Fxx[0].speech_activity_Q8, encControl.toMono, psEnc.state_Fxx[0].fs_kHz, psEnc.state_Fxx[0].frame_length); psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded] = midOnlyFlagBoxed.Val; if (midOnlyFlagBoxed.Val == 0) { /* Reset side channel encoder memory for first frame with side coding */ if (psEnc.prev_decode_only_middle == 1) { psEnc.state_Fxx[1].sShape.Reset(); psEnc.state_Fxx[1].sPrefilt.Reset(); psEnc.state_Fxx[1].sNSQ.Reset(); Arrays.MemSetShort(psEnc.state_Fxx[1].prev_NLSFq_Q15, 0, SilkConstants.MAX_LPC_ORDER); Arrays.MemSetInt(psEnc.state_Fxx[1].sLP.In_LP_State, 0, 2); psEnc.state_Fxx[1].prevLag = 100; psEnc.state_Fxx[1].sNSQ.lagPrev = 100; psEnc.state_Fxx[1].sShape.LastGainIndex = 10; psEnc.state_Fxx[1].prevSignalType = SilkConstants.TYPE_NO_VOICE_ACTIVITY; psEnc.state_Fxx[1].sNSQ.prev_gain_Q16 = 65536; psEnc.state_Fxx[1].first_frame_after_reset = 1; } psEnc.state_Fxx[1].silk_encode_do_VAD(); } else { psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] = 0; } if (prefillFlag == 0) { Stereo.silk_stereo_encode_pred(psRangeEnc, psEnc.sStereo.predIx[psEnc.state_Fxx[0].nFramesEncoded]); if (psEnc.state_Fxx[1].VAD_flags[psEnc.state_Fxx[0].nFramesEncoded] == 0) { Stereo.silk_stereo_encode_mid_only(psRangeEnc, psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded]); } } } else { /* Buffering */ Array.Copy(psEnc.sStereo.sMid, psEnc.state_Fxx[0].inputBuf, 2); Array.Copy(psEnc.state_Fxx[0].inputBuf, psEnc.state_Fxx[0].frame_length, psEnc.sStereo.sMid, 0, 2); } psEnc.state_Fxx[0].silk_encode_do_VAD(); /* Encode */ for (n = 0; n < encControl.nChannelsInternal; n++) { int maxBits, useCBR; /* Handling rate constraints */ maxBits = encControl.maxBits; if (tot_blocks == 2 && curr_block == 0) { maxBits = maxBits * 3 / 5; } else if (tot_blocks == 3) { if (curr_block == 0) { maxBits = maxBits * 2 / 5; } else if (curr_block == 1) { maxBits = maxBits * 3 / 4; } } useCBR = (encControl.useCBR != 0 && curr_block == tot_blocks - 1) ? 1 : 0; if (encControl.nChannelsInternal == 1) { channelRate_bps = TargetRate_bps; } else { channelRate_bps = MStargetRates_bps[n]; if (n == 0 && MStargetRates_bps[1] > 0) { useCBR = 0; /* Give mid up to 1/2 of the max bits for that frame */ maxBits -= encControl.maxBits / (tot_blocks * 2); } } if (channelRate_bps > 0) { int condCoding; psEnc.state_Fxx[n].silk_control_SNR(channelRate_bps); /* Use independent coding if no previous frame available */ if (psEnc.state_Fxx[0].nFramesEncoded - n <= 0) { condCoding = SilkConstants.CODE_INDEPENDENTLY; } else if (n > 0 && psEnc.prev_decode_only_middle != 0) { /* If we skipped a side frame in this packet, we don't * need LTP scaling; the LTP state is well-defined. */ condCoding = SilkConstants.CODE_INDEPENDENTLY_NO_LTP_SCALING; } else { condCoding = SilkConstants.CODE_CONDITIONALLY; } ret += psEnc.state_Fxx[n].silk_encode_frame(nBytesOut, psRangeEnc, condCoding, maxBits, useCBR); Inlines.OpusAssert(ret == SilkError.SILK_NO_ERROR); } psEnc.state_Fxx[n].controlled_since_last_payload = 0; psEnc.state_Fxx[n].inputBufIx = 0; psEnc.state_Fxx[n].nFramesEncoded++; } psEnc.prev_decode_only_middle = psEnc.sStereo.mid_only_flags[psEnc.state_Fxx[0].nFramesEncoded - 1]; /* Insert VAD and FEC flags at beginning of bitstream */ if (nBytesOut.Val > 0 && psEnc.state_Fxx[0].nFramesEncoded == psEnc.state_Fxx[0].nFramesPerPacket) { flags = 0; for (n = 0; n < encControl.nChannelsInternal; n++) { for (i = 0; i < psEnc.state_Fxx[n].nFramesPerPacket; i++) { flags = Inlines.silk_LSHIFT(flags, 1); flags |= (int)psEnc.state_Fxx[n].VAD_flags[i]; } flags = Inlines.silk_LSHIFT(flags, 1); flags |= (int)psEnc.state_Fxx[n].LBRR_flag; } if (prefillFlag == 0) { psRangeEnc.enc_patch_initial_bits((uint)flags, (uint)((psEnc.state_Fxx[0].nFramesPerPacket + 1) * encControl.nChannelsInternal)); } /* Return zero bytes if all channels DTXed */ if (psEnc.state_Fxx[0].inDTX != 0 && (encControl.nChannelsInternal == 1 || psEnc.state_Fxx[1].inDTX != 0)) { nBytesOut.Val = 0; } psEnc.nBitsExceeded += nBytesOut.Val * 8; psEnc.nBitsExceeded -= Inlines.silk_DIV32_16(Inlines.silk_MUL(encControl.bitRate, encControl.payloadSize_ms), 1000); psEnc.nBitsExceeded = Inlines.silk_LIMIT(psEnc.nBitsExceeded, 0, 10000); /* Update flag indicating if bandwidth switching is allowed */ speech_act_thr_for_switch_Q8 = Inlines.silk_SMLAWB(((int)((TuningParameters.SPEECH_ACTIVITY_DTX_THRES) * ((long)1 << (8)) + 0.5)) /*Inlines.SILK_CONST(TuningParameters.SPEECH_ACTIVITY_DTX_THRES, 8)*/, ((int)(((1 - TuningParameters.SPEECH_ACTIVITY_DTX_THRES) / TuningParameters.MAX_BANDWIDTH_SWITCH_DELAY_MS) * ((long)1 << (16 + 8)) + 0.5)) /*Inlines.SILK_CONST((1 - TuningParameters.SPEECH_ACTIVITY_DTX_THRES) / TuningParameters.MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8)*/, psEnc.timeSinceSwitchAllowed_ms); if (psEnc.state_Fxx[0].speech_activity_Q8 < speech_act_thr_for_switch_Q8) { psEnc.allowBandwidthSwitch = 1; psEnc.timeSinceSwitchAllowed_ms = 0; } else { psEnc.allowBandwidthSwitch = 0; psEnc.timeSinceSwitchAllowed_ms += encControl.payloadSize_ms; } } if (nSamplesIn == 0) { break; } } else { break; } curr_block++; } psEnc.nPrevChannelsInternal = encControl.nChannelsInternal; encControl.allowBandwidthSwitch = psEnc.allowBandwidthSwitch; encControl.inWBmodeWithoutVariableLP = (psEnc.state_Fxx[0].fs_kHz == 16 && psEnc.state_Fxx[0].sLP.mode == 0) ? 1 : 0; encControl.internalSampleRate = Inlines.silk_SMULBB(psEnc.state_Fxx[0].fs_kHz, 1000); encControl.stereoWidth_Q14 = encControl.toMono != 0 ? 0 : psEnc.sStereo.smth_width_Q14; if (prefillFlag != 0) { encControl.payloadSize_ms = tmp_payloadSize_ms; encControl.complexity = tmp_complexity; for (n = 0; n < encControl.nChannelsInternal; n++) { psEnc.state_Fxx[n].controlled_since_last_payload = 0; psEnc.state_Fxx[n].prefillFlag = 0; } } return(ret); }
internal static void encode_pulses(int[] _y, int _n, int _k, EntropyCoder _enc) { Inlines.OpusAssert(_k > 0); _enc.enc_uint(icwrs(_n, _y), CELT_PVQ_V(_n, _k)); }