/// <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 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 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 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 int opus_decode_frame(byte[] data, int data_ptr, int len, short[] pcm, int pcm_ptr, int frame_size, int decode_fec) { SilkDecoder silk_dec; CeltDecoder celt_dec; int i, silk_ret = 0, celt_ret = 0; EntropyCoder dec = new EntropyCoder(); // porting note: stack var int silk_frame_size; int pcm_silk_size; short[] pcm_silk; int pcm_transition_silk_size; short[] pcm_transition_silk; int pcm_transition_celt_size; short[] pcm_transition_celt; short[] pcm_transition = null; int redundant_audio_size; short[] redundant_audio; int audiosize; OpusMode mode; int transition = 0; int start_band; int redundancy = 0; int redundancy_bytes = 0; int celt_to_silk = 0; int c; int F2_5, F5, F10, F20; int[] window; uint redundant_rng = 0; int celt_accum; silk_dec = this.SilkDecoder; celt_dec = this.Celt_Decoder; F20 = this.Fs / 50; F10 = F20 >> 1; F5 = F10 >> 1; F2_5 = F5 >> 1; if (frame_size < F2_5) { return(OpusError.OPUS_BUFFER_TOO_SMALL); } /* Limit frame_size to avoid excessive stack allocations. */ frame_size = Inlines.IMIN(frame_size, this.Fs / 25 * 3); /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ if (len <= 1) { data = null; /* In that case, don't conceal more than what the ToC says */ frame_size = Inlines.IMIN(frame_size, this.frame_size); } if (data != null) { audiosize = this.frame_size; mode = this.mode; dec.dec_init(data, data_ptr, (uint)len); } else { audiosize = frame_size; mode = this.prev_mode; if (mode == 0) { /* If we haven't got any packet yet, all we can do is return zeros */ for (i = pcm_ptr; i < pcm_ptr + (audiosize * this.channels); i++) { pcm[i] = 0; } return(audiosize); } /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), * 10, or 20 (e.g. 12.5 or 30 ms). */ if (audiosize > F20) { do { int ret = opus_decode_frame(null, 0, 0, pcm, pcm_ptr, Inlines.IMIN(audiosize, F20), 0); if (ret < 0) { return(ret); } pcm_ptr += ret * this.channels; audiosize -= ret; } while (audiosize > 0); return(frame_size); } else if (audiosize < F20) { if (audiosize > F10) { audiosize = F10; } else if (mode != OpusMode.MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) { audiosize = F5; } } } /* In fixed-point, we can tell CELT to do the accumulation on top of the * SILK PCM buffer. This saves some stack space. */ celt_accum = ((mode != OpusMode.MODE_CELT_ONLY) && (frame_size >= F10)) ? 1 : 0; pcm_transition_silk_size = 0; pcm_transition_celt_size = 0; if (data != null && this.prev_mode > 0 && ( (mode == OpusMode.MODE_CELT_ONLY && this.prev_mode != OpusMode.MODE_CELT_ONLY && (this.prev_redundancy == 0)) || (mode != OpusMode.MODE_CELT_ONLY && this.prev_mode == OpusMode.MODE_CELT_ONLY)) ) { transition = 1; /* Decide where to allocate the stack memory for pcm_transition */ if (mode == OpusMode.MODE_CELT_ONLY) { pcm_transition_celt_size = F5 * this.channels; } else { pcm_transition_silk_size = F5 * this.channels; } } pcm_transition_celt = new short[pcm_transition_celt_size]; if (transition != 0 && mode == OpusMode.MODE_CELT_ONLY) { pcm_transition = pcm_transition_celt; opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0); } if (audiosize > frame_size) { /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ return(OpusError.OPUS_BAD_ARG); } else { frame_size = audiosize; } /* Don't allocate any memory when in CELT-only mode */ pcm_silk_size = (mode != OpusMode.MODE_CELT_ONLY && (celt_accum == 0)) ? Inlines.IMAX(F10, frame_size) * this.channels : 0; pcm_silk = new short[pcm_silk_size]; /* SILK processing */ if (mode != OpusMode.MODE_CELT_ONLY) { int lost_flag, decoded_samples; short[] pcm_ptr2; int pcm_ptr2_ptr = 0; if (celt_accum != 0) { pcm_ptr2 = pcm; pcm_ptr2_ptr = pcm_ptr; } else { pcm_ptr2 = pcm_silk; pcm_ptr2_ptr = 0; } if (this.prev_mode == OpusMode.MODE_CELT_ONLY) { DecodeAPI.silk_InitDecoder(silk_dec); } /* The SILK PLC cannot produce frames of less than 10 ms */ this.DecControl.payloadSize_ms = Inlines.IMAX(10, 1000 * audiosize / this.Fs); if (data != null) { this.DecControl.nChannelsInternal = this.stream_channels; if (mode == OpusMode.MODE_SILK_ONLY) { if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND) { this.DecControl.internalSampleRate = 8000; } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND) { this.DecControl.internalSampleRate = 12000; } else if (this.bandwidth == OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND) { this.DecControl.internalSampleRate = 16000; } else { this.DecControl.internalSampleRate = 16000; Inlines.OpusAssert(false); } } else { /* Hybrid mode */ this.DecControl.internalSampleRate = 16000; } } lost_flag = data == null ? 1 : 2 * decode_fec; decoded_samples = 0; do { /* Call SILK decoder */ int first_frame = (decoded_samples == 0) ? 1 : 0; silk_ret = DecodeAPI.silk_Decode(silk_dec, this.DecControl, lost_flag, first_frame, dec, pcm_ptr2, pcm_ptr2_ptr, out silk_frame_size); if (silk_ret != 0) { if (lost_flag != 0) { /* PLC failure should not be fatal */ silk_frame_size = frame_size; Arrays.MemSetWithOffset <short>(pcm_ptr2, 0, pcm_ptr2_ptr, frame_size * this.channels); } else { return(OpusError.OPUS_INTERNAL_ERROR); } } pcm_ptr2_ptr += (silk_frame_size * this.channels); decoded_samples += silk_frame_size; } while (decoded_samples < frame_size); } start_band = 0; if (decode_fec == 0 && mode != OpusMode.MODE_CELT_ONLY && data != null && dec.tell() + 17 + 20 * (this.mode == OpusMode.MODE_HYBRID ? 1 : 0) <= 8 * len) { /* Check if we have a redundant 0-8 kHz band */ if (mode == OpusMode.MODE_HYBRID) { redundancy = dec.dec_bit_logp(12); } else { redundancy = 1; } if (redundancy != 0) { celt_to_silk = dec.dec_bit_logp(1); /* redundancy_bytes will be at least two, in the non-hybrid * case due to the ec_tell() check above */ redundancy_bytes = mode == OpusMode.MODE_HYBRID ? (int)dec.dec_uint(256) + 2 : len - ((dec.tell() + 7) >> 3); len -= redundancy_bytes; /* This is a sanity check. It should never happen for a valid * packet, so the exact behaviour is not normative. */ if (len * 8 < dec.tell()) { len = 0; redundancy_bytes = 0; redundancy = 0; } /* Shrink decoder because of raw bits */ dec.storage = (uint)(dec.storage - redundancy_bytes); } } if (mode != OpusMode.MODE_CELT_ONLY) { start_band = 17; } { int endband = 21; switch (this.bandwidth) { case OpusBandwidth.OPUS_BANDWIDTH_NARROWBAND: endband = 13; break; case OpusBandwidth.OPUS_BANDWIDTH_MEDIUMBAND: case OpusBandwidth.OPUS_BANDWIDTH_WIDEBAND: endband = 17; break; case OpusBandwidth.OPUS_BANDWIDTH_SUPERWIDEBAND: endband = 19; break; case OpusBandwidth.OPUS_BANDWIDTH_FULLBAND: endband = 21; break; } celt_dec.SetEndBand(endband); celt_dec.SetChannels(this.stream_channels); } if (redundancy != 0) { transition = 0; pcm_transition_silk_size = 0; } pcm_transition_silk = new short[pcm_transition_silk_size]; if (transition != 0 && mode != OpusMode.MODE_CELT_ONLY) { pcm_transition = pcm_transition_silk; opus_decode_frame(null, 0, 0, pcm_transition, 0, Inlines.IMIN(F5, audiosize), 0); } /* Only allocation memory for redundancy if/when needed */ redundant_audio_size = redundancy != 0 ? F5 * this.channels : 0; redundant_audio = new short[redundant_audio_size]; /* 5 ms redundant frame for CELT->SILK*/ if (redundancy != 0 && celt_to_silk != 0) { celt_dec.SetStartBand(0); celt_dec.celt_decode_with_ec(data, (data_ptr + len), redundancy_bytes, redundant_audio, 0, F5, null, 0); redundant_rng = celt_dec.GetFinalRange(); } /* MUST be after PLC */ celt_dec.SetStartBand(start_band); if (mode != OpusMode.MODE_SILK_ONLY) { int celt_frame_size = Inlines.IMIN(F20, frame_size); /* Make sure to discard any previous CELT state */ if (mode != this.prev_mode && this.prev_mode > 0 && this.prev_redundancy == 0) { celt_dec.ResetState(); } /* Decode CELT */ celt_ret = celt_dec.celt_decode_with_ec(decode_fec != 0 ? null : data, data_ptr, len, pcm, pcm_ptr, celt_frame_size, dec, celt_accum); } else { if (celt_accum == 0) { for (i = pcm_ptr; i < (frame_size * this.channels) + pcm_ptr; i++) { pcm[i] = 0; } } /* For hybrid -> SILK transitions, we let the CELT MDCT * do a fade-out by decoding a silence frame */ if (this.prev_mode == OpusMode.MODE_HYBRID && !(redundancy != 0 && celt_to_silk != 0 && this.prev_redundancy != 0)) { celt_dec.SetStartBand(0); celt_dec.celt_decode_with_ec(SILENCE, 0, 2, pcm, pcm_ptr, F2_5, null, celt_accum); } } if (mode != OpusMode.MODE_CELT_ONLY && celt_accum == 0) { for (i = 0; i < frame_size * this.channels; i++) { pcm[pcm_ptr + i] = Inlines.SAT16(Inlines.ADD32(pcm[pcm_ptr + i], pcm_silk[i])); } } window = celt_dec.GetMode().window; /* 5 ms redundant frame for SILK->CELT */ if (redundancy != 0 && celt_to_silk == 0) { celt_dec.ResetState(); celt_dec.SetStartBand(0); celt_dec.celt_decode_with_ec(data, data_ptr + len, redundancy_bytes, redundant_audio, 0, F5, null, 0); redundant_rng = celt_dec.GetFinalRange(); CodecHelpers.smooth_fade(pcm, pcm_ptr + this.channels * (frame_size - F2_5), redundant_audio, this.channels * F2_5, pcm, (pcm_ptr + this.channels * (frame_size - F2_5)), F2_5, this.channels, window, this.Fs); } if (redundancy != 0 && celt_to_silk != 0) { for (c = 0; c < this.channels; c++) { for (i = 0; i < F2_5; i++) { pcm[this.channels * i + c + pcm_ptr] = redundant_audio[this.channels * i + c]; } } CodecHelpers.smooth_fade(redundant_audio, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)), pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs); } if (transition != 0) { if (audiosize >= F5) { for (i = 0; i < this.channels * F2_5; i++) { pcm[i] = pcm_transition[i]; } CodecHelpers.smooth_fade(pcm_transition, (this.channels * F2_5), pcm, (pcm_ptr + (this.channels * F2_5)), pcm, (pcm_ptr + (this.channels * F2_5)), F2_5, this.channels, window, this.Fs); } else { /* Not enough time to do a clean transition, but we do it anyway * This will not preserve amplitude perfectly and may introduce * a bit of temporal aliasing, but it shouldn't be too bad and * that's pretty much the best we can do. In any case, generating this * transition is pretty silly in the first place */ CodecHelpers.smooth_fade(pcm_transition, 0, pcm, pcm_ptr, pcm, pcm_ptr, F2_5, this.channels, window, this.Fs); } } if (this.decode_gain != 0) { int gain; gain = Inlines.celt_exp2(Inlines.MULT16_16_P15(((short)(0.5 + (6.48814081e-4f) * (((int)1) << (25)))) /*Inlines.QCONST16(6.48814081e-4f, 25)*/, this.decode_gain)); for (i = pcm_ptr; i < pcm_ptr + (frame_size * this.channels); i++) { int x; x = Inlines.MULT16_32_P16(pcm[i], gain); pcm[i] = (short)Inlines.SATURATE(x, 32767); } } if (len <= 1) { this.rangeFinal = 0; } else { this.rangeFinal = dec.rng ^ redundant_rng; } this.prev_mode = mode; this.prev_redundancy = (redundancy != 0 && celt_to_silk == 0) ? 1 : 0; return(celt_ret < 0 ? celt_ret : audiosize); }