internal static void celt_fir( int[] x, int x_ptr, int[] num, int num_ptr, int[] y, int y_ptr, int N, int ord, int[] mem ) { int i, j; int[] rnum = new int[ord]; int[] local_x = new int[N + ord]; for (i = 0; i < ord; i++) { rnum[i] = num[num_ptr + ord - i - 1]; } for (i = 0; i < ord; i++) { local_x[i] = mem[ord - i - 1]; } for (i = 0; i < N; i++) { local_x[i + ord] = x[x_ptr + i]; } for (i = 0; i < ord; i++) { mem[i] = x[x_ptr + N - i - 1]; } for (i = 0; i < N - 3; i += 4) { int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; xcorr_kernel(rnum, local_x, i, ref sum0, ref sum1, ref sum2, ref sum3, ord); y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT)))); y[y_ptr + i + 1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT)))); y[y_ptr + i + 2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT)))); y[y_ptr + i + 3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i + 3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT)))); } for (; i < N; i++) { int sum = 0; for (j = 0; j < ord; j++) { sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]); } y[y_ptr + i] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[x_ptr + i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT)))); } }
internal static void find_best_pitch(int[] xcorr, int[] y, int len, int max_pitch, int[] best_pitch, int yshift, int maxcorr ) { int i, j; int Syy = 1; int best_num_0; int best_num_1; int best_den_0; int best_den_1; int xshift = Inlines.celt_ilog2(maxcorr) - 14; best_num_0 = -1; best_num_1 = -1; best_den_0 = 0; best_den_1 = 0; best_pitch[0] = 0; best_pitch[1] = 1; for (j = 0; j < len; j++) { Syy = Inlines.ADD32(Syy, Inlines.SHR32(Inlines.MULT16_16(y[j], y[j]), yshift)); } for (i = 0; i < max_pitch; i++) { if (xcorr[i] > 0) { int num; int xcorr16; xcorr16 = Inlines.EXTRACT16(Inlines.VSHR32(xcorr[i], xshift)); num = Inlines.MULT16_16_Q15((xcorr16), (xcorr16)); if (Inlines.MULT16_32_Q15(num, best_den_1) > Inlines.MULT16_32_Q15(best_num_1, Syy)) { if (Inlines.MULT16_32_Q15(num, best_den_0) > Inlines.MULT16_32_Q15(best_num_0, Syy)) { best_num_1 = best_num_0; best_den_1 = best_den_0; best_pitch[1] = best_pitch[0]; best_num_0 = num; best_den_0 = Syy; best_pitch[0] = i; } else { best_num_1 = num; best_den_1 = Syy; best_pitch[1] = i; } } } Syy += Inlines.SHR32(Inlines.MULT16_16(y[i + len], y[i + len]), yshift) - Inlines.SHR32(Inlines.MULT16_16(y[i], y[i]), yshift); Syy = Inlines.MAX32(1, Syy); } }
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 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); }
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); }
internal static unsafe void celt_fir( short *x, short[] num, short *y, int N, int ord, short[] mem ) { int i, j; short[] rnum = new short[ord]; short[] local_x = new short[N + ord]; fixed(short *prnum = rnum, plocal_x = local_x) { for (i = 0; i < ord; i++) { prnum[i] = num[ord - i - 1]; } for (i = 0; i < ord; i++) { plocal_x[i] = mem[ord - i - 1]; } for (i = 0; i < N; i++) { plocal_x[i + ord] = x[i]; } for (i = 0; i < ord; i++) { mem[i] = x[N - i - 1]; } short *py = y; for (i = 0; i < N - 3; i += 4) { int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; short *local_x2 = plocal_x + i; xcorr_kernel(prnum, local_x2, ref sum0, ref sum1, ref sum2, ref sum3, ord); py[0] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT)))); py[1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i + 1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT)))); py[2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i + 2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT)))); py[3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i + 3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT)))); py += 4; } for (; i < N; i++) { int sum = 0; for (j = 0; j < ord; j++) { sum = Inlines.MAC16_16(sum, prnum[j], plocal_x[i + j]); } *py = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(x[i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT)))); py++; } } }
internal static unsafe void celt_fir( int *px, int *pnum, int *py, int N, int ord, int[] mem ) { int i, j; int[] rnum = new int[ord]; int[] local_x = new int[N + ord]; fixed(int *prnum = rnum, plocal_x_base = local_x) { for (i = 0; i < ord; i++) { rnum[i] = pnum[ord - i - 1]; } for (i = 0; i < ord; i++) { local_x[i] = mem[ord - i - 1]; } for (i = 0; i < N; i++) { local_x[i + ord] = px[i]; } for (i = 0; i < ord; i++) { mem[i] = px[N - i - 1]; } int *px2 = px; for (i = 0; i < N - 3; i += 4) { int sum0 = 0, sum1 = 0, sum2 = 0, sum3 = 0; int *plocal_x = plocal_x_base + i; xcorr_kernel(prnum, plocal_x, ref sum0, ref sum1, ref sum2, ref sum3, ord); py[0] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[0]), Inlines.PSHR32(sum0, CeltConstants.SIG_SHIFT)))); py[1] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[1]), Inlines.PSHR32(sum1, CeltConstants.SIG_SHIFT)))); py[2] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[2]), Inlines.PSHR32(sum2, CeltConstants.SIG_SHIFT)))); py[3] = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px2[3]), Inlines.PSHR32(sum3, CeltConstants.SIG_SHIFT)))); py += 4; px2 += 4; } for (; i < N; i++) { int sum = 0; for (j = 0; j < ord; j++) { sum = Inlines.MAC16_16(sum, rnum[j], local_x[i + j]); } *py = Inlines.SATURATE16((Inlines.ADD32(Inlines.EXTEND32(px[i]), Inlines.PSHR32(sum, CeltConstants.SIG_SHIFT)))); py++; } } }