//Initialization. Material is duplicated due to previous implementation - currently serves no purpose. private void Awake() { rb = GetComponent <Rigidbody>(); mr = GetComponent <MeshRenderer>(); Material newMat = Instantiate(mr.material); mr.material = newMat; start = new VQ(transform.position, transform.rotation); }
internal void celt_decode_lost(int N, int LM) { int c; int i; int C = this.channels; int[][] out_syn = new int[2][]; int[] out_syn_ptrs = new int[2]; CeltMode mode; int nbEBands; int overlap; int noise_based; short[] eBands; mode = this.mode; nbEBands = mode.nbEBands; overlap = mode.overlap; eBands = mode.eBands; c = 0; do { out_syn[c] = this.decode_mem[c]; out_syn_ptrs[c] = CeltConstants.DECODE_BUFFER_SIZE - N; } while (++c < C); noise_based = (loss_count >= 5 || start != 0) ? 1 : 0; if (noise_based != 0) { /* Noise-based PLC/CNG */ int[][] X; uint seed; int end; int effEnd; int decay; end = this.end; effEnd = Inlines.IMAX(start, Inlines.IMIN(end, mode.effEBands)); X = Arrays.InitTwoDimensionalArray <int>(C, N); /**< Interleaved normalised MDCTs */ /* Energy decay */ decay = loss_count == 0 ? ((short)(0.5 + (1.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(1.5f, CeltConstants.DB_SHIFT)*/ : ((short)(0.5 + (0.5f) * (((int)1) << (CeltConstants.DB_SHIFT)))) /*Inlines.QCONST16(0.5f, CeltConstants.DB_SHIFT)*/; c = 0; do { for (i = start; i < end; i++) { this.oldEBands[c * nbEBands + i] = Inlines.MAX16(backgroundLogE[c * nbEBands + i], this.oldEBands[c * nbEBands + i] - decay); } } while (++c < C); seed = this.rng; for (c = 0; c < C; c++) { for (i = start; i < effEnd; i++) { int j; int boffs; int blen; boffs = (eBands[i] << LM); blen = (eBands[i + 1] - eBands[i]) << LM; for (j = 0; j < blen; j++) { seed = Bands.celt_lcg_rand(seed); X[c][boffs + j] = (unchecked ((int)seed) >> 20); } VQ.renormalise_vector(X[c], 0, blen, CeltConstants.Q15ONE); } } this.rng = seed; c = 0; do { Arrays.MemMoveInt(this.decode_mem[c], N, 0, CeltConstants.DECODE_BUFFER_SIZE - N + (overlap >> 1)); } while (++c < C); CeltCommon.celt_synthesis(mode, X, out_syn, out_syn_ptrs, this.oldEBands, start, effEnd, C, C, 0, LM, this.downsample, 0); } else { /* Pitch-based PLC */ int[] window; int fade = CeltConstants.Q15ONE; int pitch_index; int[] etmp; int[] exc; if (loss_count == 0) { this.last_pitch_index = pitch_index = CeltCommon.celt_plc_pitch_search(this.decode_mem, C); } else { pitch_index = this.last_pitch_index; fade = ((short)(0.5 + (.8f) * (((int)1) << (15)))) /*Inlines.QCONST16(.8f, 15)*/; } etmp = new int[overlap]; exc = new int[CeltConstants.MAX_PERIOD]; window = mode.window; c = 0; do { int decay; int attenuation; int S1 = 0; int[] buf; int extrapolation_offset; int extrapolation_len; int exc_length; int j; buf = this.decode_mem[c]; for (i = 0; i < CeltConstants.MAX_PERIOD; i++) { exc[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.MAX_PERIOD + i], CeltConstants.SIG_SHIFT); } if (loss_count == 0) { int[] ac = new int[CeltConstants.LPC_ORDER + 1]; /* Compute LPC coefficients for the last MAX_PERIOD samples before * the first loss so we can work in the excitation-filter domain. */ Autocorrelation._celt_autocorr(exc, ac, window, overlap, CeltConstants.LPC_ORDER, CeltConstants.MAX_PERIOD); /* Add a noise floor of -40 dB. */ ac[0] += Inlines.SHR32(ac[0], 13); /* Use lag windowing to stabilize the Levinson-Durbin recursion. */ for (i = 1; i <= CeltConstants.LPC_ORDER; i++) { /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ ac[i] -= Inlines.MULT16_32_Q15(2 * i * i, ac[i]); } CeltLPC.celt_lpc(this.lpc[c], ac, CeltConstants.LPC_ORDER); } /* We want the excitation for 2 pitch periods in order to look for a * decaying signal, but we can't get more than MAX_PERIOD. */ exc_length = Inlines.IMIN(2 * pitch_index, CeltConstants.MAX_PERIOD); /* Initialize the LPC history with the samples just before the start * of the region for which we're computing the excitation. */ { int[] lpc_mem = new int[CeltConstants.LPC_ORDER]; for (i = 0; i < CeltConstants.LPC_ORDER; i++) { lpc_mem[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - exc_length - 1 - i], CeltConstants.SIG_SHIFT); } /* Compute the excitation for exc_length samples before the loss. */ Kernels.celt_fir(exc, (CeltConstants.MAX_PERIOD - exc_length), this.lpc[c], 0, exc, (CeltConstants.MAX_PERIOD - exc_length), exc_length, CeltConstants.LPC_ORDER, lpc_mem); } /* Check if the waveform is decaying, and if so how fast. * We do this to avoid adding energy when concealing in a segment * with decaying energy. */ { int E1 = 1, E2 = 1; int decay_length; int shift = Inlines.IMAX(0, 2 * Inlines.celt_zlog2(Inlines.celt_maxabs16(exc, (CeltConstants.MAX_PERIOD - exc_length), exc_length)) - 20); decay_length = exc_length >> 1; for (i = 0; i < decay_length; i++) { int e; e = exc[CeltConstants.MAX_PERIOD - decay_length + i]; E1 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift); e = exc[CeltConstants.MAX_PERIOD - 2 * decay_length + i]; E2 += Inlines.SHR32(Inlines.MULT16_16(e, e), shift); } E1 = Inlines.MIN32(E1, E2); decay = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(E1, 1), E2)); } /* Move the decoder memory one frame to the left to give us room to * add the data for the new frame. We ignore the overlap that extends * past the end of the buffer, because we aren't going to use it. */ Arrays.MemMoveInt(buf, N, 0, CeltConstants.DECODE_BUFFER_SIZE - N); /* Extrapolate from the end of the excitation with a period of * "pitch_index", scaling down each period by an additional factor of * "decay". */ extrapolation_offset = CeltConstants.MAX_PERIOD - pitch_index; /* We need to extrapolate enough samples to cover a complete MDCT * window (including overlap/2 samples on both sides). */ extrapolation_len = N + overlap; /* We also apply fading if this is not the first loss. */ attenuation = Inlines.MULT16_16_Q15(fade, decay); for (i = j = 0; i < extrapolation_len; i++, j++) { int tmp; if (j >= pitch_index) { j -= pitch_index; attenuation = Inlines.MULT16_16_Q15(attenuation, decay); } buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] = Inlines.SHL32((Inlines.MULT16_16_Q15(attenuation, exc[extrapolation_offset + j])), CeltConstants.SIG_SHIFT); /* Compute the energy of the previously decoded signal whose * excitation we're copying. */ tmp = Inlines.ROUND16( buf[CeltConstants.DECODE_BUFFER_SIZE - CeltConstants.MAX_PERIOD - N + extrapolation_offset + j], CeltConstants.SIG_SHIFT); S1 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8); } { int[] lpc_mem = new int[CeltConstants.LPC_ORDER]; /* Copy the last decoded samples (prior to the overlap region) to * synthesis filter memory so we can have a continuous signal. */ for (i = 0; i < CeltConstants.LPC_ORDER; i++) { lpc_mem[i] = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - N - 1 - i], CeltConstants.SIG_SHIFT); } /* Apply the synthesis filter to convert the excitation back into * the signal domain. */ CeltLPC.celt_iir(buf, CeltConstants.DECODE_BUFFER_SIZE - N, this.lpc[c], buf, CeltConstants.DECODE_BUFFER_SIZE - N, extrapolation_len, CeltConstants.LPC_ORDER, lpc_mem); } /* Check if the synthesis energy is higher than expected, which can * happen with the signal changes during our window. If so, * attenuate. */ { int S2 = 0; for (i = 0; i < extrapolation_len; i++) { int tmp = Inlines.ROUND16(buf[CeltConstants.DECODE_BUFFER_SIZE - N + i], CeltConstants.SIG_SHIFT); S2 += Inlines.SHR32(Inlines.MULT16_16(tmp, tmp), 8); } /* This checks for an "explosion" in the synthesis. */ if (!(S1 > Inlines.SHR32(S2, 2))) { for (i = 0; i < extrapolation_len; i++) { buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] = 0; } } else if (S1 < S2) { int ratio = Inlines.celt_sqrt(Inlines.frac_div32(Inlines.SHR32(S1, 1) + 1, S2 + 1)); for (i = 0; i < overlap; i++) { int tmp_g = CeltConstants.Q15ONE - Inlines.MULT16_16_Q15(window[i], CeltConstants.Q15ONE - ratio); buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] = Inlines.MULT16_32_Q15(tmp_g, buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]); } for (i = overlap; i < extrapolation_len; i++) { buf[CeltConstants.DECODE_BUFFER_SIZE - N + i] = Inlines.MULT16_32_Q15(ratio, buf[CeltConstants.DECODE_BUFFER_SIZE - N + i]); } } } /* Apply the pre-filter to the MDCT overlap for the next frame because * the post-filter will be re-applied in the decoder after the MDCT * overlap. */ CeltCommon.comb_filter(etmp, 0, buf, CeltConstants.DECODE_BUFFER_SIZE, this.postfilter_period, this.postfilter_period, overlap, -this.postfilter_gain, -this.postfilter_gain, this.postfilter_tapset, this.postfilter_tapset, null, 0); /* Simulate TDAC on the concealed audio so that it blends with the * MDCT of the next frame. */ for (i = 0; i < overlap / 2; i++) { buf[CeltConstants.DECODE_BUFFER_SIZE + i] = Inlines.MULT16_32_Q15(window[i], etmp[overlap - 1 - i]) + Inlines.MULT16_32_Q15(window[overlap - i - 1], etmp[i]); } } while (++c < C); } this.loss_count = loss_count + 1; }
/// <summary> /// Codebook Search Quantification (Split Shape). /// </summary> /// <param name="target"></param> /// <param name="ak">LPCs for this subframe</param> /// <param name="awk1">Weighted LPCs for this subframe</param> /// <param name="awk2">Weighted LPCs for this subframe</param> /// <param name="p">number of LPC coeffs</param> /// <param name="nsf">number of samples in subframe</param> /// <param name="exc">excitation array.</param> /// <param name="es">position in excitation array.</param> /// <param name="r"></param> /// <param name="bits">Speex bits buffer.</param> /// <param name="complexity"></param> public override sealed void Quant(float[] target, float[] ak, float[] awk1, float[] awk2, int p, int nsf, float[] exc, int es, float[] r, Bits bits, int complexity) { int i, j, k, m, n, q; float[] resp; float[] ndist, odist; int[] best_index; float[] best_dist; int N = complexity; if (N > 10) { N = 10; } resp = new float[_shapeCbSize * _subVectSize]; best_index = new int[N]; best_dist = new float[N]; ndist = new float[N]; odist = new float[N]; for (i = 0; i < N; i++) { for (j = 0; j < _nbSubvect; j++) { _nind[i][j] = _oind[i][j] = -1; } } for (j = 0; j < N; j++) { for (i = 0; i < nsf; i++) { _ot[j][i] = target[i]; } } // System.arraycopy(target, 0, t, 0, nsf); /* Pre-compute codewords response and energy */ for (i = 0; i < _shapeCbSize; i++) { int res; int shape; res = i * _subVectSize; shape = i * _subVectSize; /* Compute codeword response using convolution with impulse response */ for (j = 0; j < _subVectSize; j++) { resp[res + j] = 0; for (k = 0; k <= j; k++) { resp[res + j] += 0.03125f * _shapeCb[shape + k] * r[j - k]; } } /* Compute codeword energy */ E[i] = 0; for (j = 0; j < _subVectSize; j++) { E[i] += resp[res + j] * resp[res + j]; } } for (j = 0; j < N; j++) { odist[j] = 0; } /*For all subvectors*/ for (i = 0; i < _nbSubvect; i++) { int offset = i * _subVectSize; /*"erase" nbest list*/ for (j = 0; j < N; j++) { ndist[j] = -1; } /*For all n-bests of previous subvector*/ for (j = 0; j < N; j++) { /*Find new n-best based on previous n-best j*/ if (_haveSign != 0) { VQ.nbest_sign(_ot[j], offset, resp, _subVectSize, _shapeCbSize, E, N, best_index, best_dist); } else { VQ.nbest(_ot[j], offset, resp, _subVectSize, _shapeCbSize, E, N, best_index, best_dist); } /*For all new n-bests*/ for (k = 0; k < N; k++) { float[] ct; float err = 0; ct = _ot[j]; /*update target*/ /*previous target*/ for (m = offset; m < offset + _subVectSize; m++) { t[m] = ct[m]; } /* New code: update only enough of the target to calculate error*/ { int rind; int res; float sign = 1; rind = best_index[k]; if (rind >= _shapeCbSize) { sign = -1; rind -= _shapeCbSize; } res = rind * _subVectSize; if (sign > 0) { for (m = 0; m < _subVectSize; m++) { t[offset + m] -= resp[res + m]; } } else { for (m = 0; m < _subVectSize; m++) { t[offset + m] += resp[res + m]; } } } /*compute error (distance)*/ err = odist[j]; for (m = offset; m < offset + _subVectSize; m++) { err += t[m] * t[m]; } /*update n-best list*/ if (err < ndist[N - 1] || ndist[N - 1] < -.5) { /*previous target (we don't care what happened before*/ for (m = offset + _subVectSize; m < nsf; m++) { t[m] = ct[m]; } /* New code: update the rest of the target only if it's worth it */ for (m = 0; m < _subVectSize; m++) { float g; int rind; float sign = 1; rind = best_index[k]; if (rind >= _shapeCbSize) { sign = -1; rind -= _shapeCbSize; } g = sign * 0.03125f * _shapeCb[rind * _subVectSize + m]; q = _subVectSize - m; for (n = offset + _subVectSize; n < nsf; n++, q++) { t[n] -= g * r[q]; } } for (m = 0; m < N; m++) { if (err < ndist[m] || ndist[m] < -.5) { for (n = N - 1; n > m; n--) { for (q = offset + _subVectSize; q < nsf; q++) { _nt[n][q] = _nt[n - 1][q]; } for (q = 0; q < _nbSubvect; q++) { _nind[n][q] = _nind[n - 1][q]; } ndist[n] = ndist[n - 1]; } for (q = offset + _subVectSize; q < nsf; q++) { _nt[m][q] = t[q]; } for (q = 0; q < _nbSubvect; q++) { _nind[m][q] = _oind[j][q]; } _nind[m][i] = best_index[k]; ndist[m] = err; break; } } } } if (i == 0) { break; } } /*update old-new data*/ /* just swap pointers instead of a long copy */ { float[][] tmp2; tmp2 = _ot; _ot = _nt; _nt = tmp2; } for (j = 0; j < N; j++) { for (m = 0; m < _nbSubvect; m++) { _oind[j][m] = _nind[j][m]; } } for (j = 0; j < N; j++) { odist[j] = ndist[j]; } } /*save indices*/ for (i = 0; i < _nbSubvect; i++) { _ind[i] = _nind[0][i]; bits.Pack(_ind[i], _shapeBits + _haveSign); } /* Put everything back together */ for (i = 0; i < _nbSubvect; i++) { int rind; float sign = 1; rind = _ind[i]; if (rind >= _shapeCbSize) { sign = -1; rind -= _shapeCbSize; } for (j = 0; j < _subVectSize; j++) { e[_subVectSize * i + j] = sign * 0.03125f * _shapeCb[rind * _subVectSize + j]; } } /* Update excitation */ for (j = 0; j < nsf; j++) { exc[es + j] += e[j]; } /* Update target */ Filters.syn_percep_zero(e, 0, ak, awk1, awk2, r2, nsf, p); for (j = 0; j < nsf; j++) { target[j] -= r2[j]; } }