namespace NSpeex { using System; internal class NbDecoder : NbCodec, IDecoder { private int count_lost; protected internal bool enhanced; protected internal Inband inband; private float[] innov2; private float last_ol_gain; private int last_pitch; private float last_pitch_gain; private float[] pitch_gain_buf; private int pitch_gain_buf_idx; protected internal Random random = new Random(); protected internal Stereo stereo = new Stereo(); public NbDecoder() { this.inband = new Inband(this.stereo); this.enhanced = true; } public virtual int Decode(Bits bits, float[] xout) { int num; int num4 = 0; float[] numArray = new float[3]; float num6 = 0f; float num7 = 0f; int num8 = 40; float num9 = 0f; float num10 = 0f; if ((bits == null) && (base.dtx_enabled != 0)) { base.submodeID = 0; } else { int num5; if (bits == null) { this.DecodeLost(xout); return 0; } do { if (bits.BitsRemaining< 5) { return -1; } if (bits.Unpack(1) != 0) { num5 = bits.Unpack(3); int n = SbCodec.SB_FRAME_SIZE[num5]; if (n < 0) { throw new InvalidFormatException("Invalid sideband mode encountered (1st sideband): " + num5); } n -= 4; bits.Advance(n); if (bits.Unpack(1) != 0) { num5 = bits.Unpack(3); n = SbCodec.SB_FRAME_SIZE[num5]; if (n < 0) { throw new InvalidFormatException("Invalid sideband mode encountered. (2nd sideband): " + num5); } n -= 4; bits.Advance(n); if (bits.Unpack(1) != 0) { throw new InvalidFormatException("More than two sideband layers found"); } } } if (bits.BitsRemaining < 4) { return 1; } num5 = bits.Unpack(4); switch (num5) { case 15: return 1; case 14: this.inband.SpeexInbandRequest(bits); break; case 13: this.inband.UserInbandRequest(bits); break; default: if (num5 > 8) { throw new InvalidFormatException("Invalid mode encountered: " + num5); } break; } } while (num5 > 8); base.submodeID = num5; } Array.Copy(base.frmBuf, base.frameSize, base.frmBuf, 0, base.bufSize - base.frameSize); Array.Copy(base.excBuf, base.frameSize, base.excBuf, 0, base.bufSize - base.frameSize); if (base.submodes[base.submodeID] == null) { Filters.Bw_lpc(0.93f, base.interp_qlpc, base.lpc, 10); float num12 = 0f; for (num = 0; num < base.frameSize; num++) { num12 += base.innov[num] * base.innov[num]; } num12 = (float)Math.Sqrt((double)(num12 / ((float)base.frameSize))); for (num = base.excIdx; num < (base.excIdx + base.frameSize); num++) { base.excBuf[num] = (float)((3f * num12) * (this.random.NextDouble() - 0.5)); } base.first = 1; Filters.Iir_mem2(base.excBuf, base.excIdx, base.lpc, base.frmBuf, base.frmIdx, base.frameSize, base.lpcSize, base.mem_sp); xout[0] = base.frmBuf[base.frmIdx] + (base.preemph * base.pre_mem); for (num = 1; num < base.frameSize; num++) { xout[num] = base.frmBuf[base.frmIdx + num] + (base.preemph * xout[num - 1]); } base.pre_mem = xout[base.frameSize - 1]; this.count_lost = 0; return 0; } base.submodes[base.submodeID].LsqQuant.Unquant(base.qlsp, base.lpcSize, bits); if (this.count_lost != 0) { float num13 = 0f; for (num = 0; num < base.lpcSize; num++) { num13 += Math.Abs((float)(base.old_qlsp[num] - base.qlsp[num])); } float num14 = (float)(0.6 * Math.Exp(-0.2 * num13)); for (num = 0; num < (2 * base.lpcSize); num++) { base.mem_sp[num] *= num14; } } if ((base.first != 0) || (this.count_lost != 0)) { num = 0; while (num < base.lpcSize) { base.old_qlsp[num] = base.qlsp[num]; num++; } } if (base.submodes[base.submodeID].LbrPitch != -1) { num4 = base.min_pitch + bits.Unpack(7); } if (base.submodes[base.submodeID].ForcedPitchGain != 0) { int num15 = bits.Unpack(4); num7 = 0.066667f * num15; } num6 = (float)Math.Exp(((double)bits.Unpack(5)) / 3.5); if (base.submodeID == 1) { if (bits.Unpack(4) == 15) { base.dtx_enabled = 1; } else { base.dtx_enabled = 0; } } if (base.submodeID > 1) { base.dtx_enabled = 0; } for (int i = 0; i < base.nbSubframes; i++) { int num26; int num27; int num30; float num32; int num18 = base.subframeSize * i; int nsi = base.frmIdx + num18; int es = base.excIdx + num18; float num21 = (1f + i) / ((float)base.nbSubframes); num = 0; while (num < base.lpcSize) { base.interp_qlsp[num] = ((1f - num21) * base.old_qlsp[num]) + (num21 * base.qlsp[num]); num++; } Lsp.Enforce_margin(base.interp_qlsp, base.lpcSize, 0.002f); num = 0; while (num < base.lpcSize) { base.interp_qlsp[num] = (float)Math.Cos((double)base.interp_qlsp[num]); num++; } base.m_lsp.Lsp2lpc(base.interp_qlsp, base.interp_qlpc, base.lpcSize); if (this.enhanced) { float num22 = 0.9f; float gamma = base.submodes[base.submodeID].LpcEnhK1; float num24 = base.submodes[base.submodeID].LpcEnhK2; float num25 = (1f - ((1f - (num22 * gamma)) / (1f - (num22 * num24)))) / num22; Filters.Bw_lpc(gamma, base.interp_qlpc, base.awk1, base.lpcSize); Filters.Bw_lpc(num24, base.interp_qlpc, base.awk2, base.lpcSize); Filters.Bw_lpc(num25, base.interp_qlpc, base.awk3, base.lpcSize); } num21 = 1f; base.pi_gain[i] = 0f; num = 0; while (num <= base.lpcSize) { base.pi_gain[i] += num21 * base.interp_qlpc[num]; num21 = -num21; num++; } num = 0; while (num < base.subframeSize) { base.excBuf[es + num] = 0f; num++; } if (base.submodes[base.submodeID].LbrPitch != -1) { int lbrPitch = base.submodes[base.submodeID].LbrPitch; if (lbrPitch != 0) { num26 = (num4 - lbrPitch) + 1; if (num26 < base.min_pitch) { num26 = base.min_pitch; } num27 = num4 + lbrPitch; if (num27 > base.max_pitch) { num27 = base.max_pitch; } } else { num26 = num27 = num4; } } else { num26 = base.min_pitch; num27 = base.max_pitch; } int pitch = base.submodes[base.submodeID].Ltp.Unquant(base.excBuf, es, num26, num7, base.subframeSize, numArray, bits, this.count_lost, num18, this.last_pitch_gain); if ((this.count_lost != 0) && (num6 < this.last_ol_gain)) { float num29 = num6 / (this.last_ol_gain + 1f); num = 0; while (num < base.subframeSize) { base.excBuf[base.excIdx + num] *= num29; num++; } } num21 = Math.Abs((float)((numArray[0] + numArray[1]) + numArray[2])); num21 = Math.Abs(numArray[1]); if (numArray[0] > 0f) { num21 += numArray[0]; } else { num21 -= 0.5f * numArray[0]; } if (numArray[2] > 0f) { num21 += numArray[2]; } else { num21 -= 0.5f * numArray[0]; } num10 += num21; if (num21 > num9) { num8 = pitch; num9 = num21; } int num31 = i * base.subframeSize; num = num31; while (num < (num31 + base.subframeSize)) { base.innov[num] = 0f; num++; } if (base.submodes[base.submodeID].HaveSubframeGain == 3) { num30 = bits.Unpack(3); num32 = (float)(num6 * Math.Exp((double)NbCodec.exc_gain_quant_scal3[num30])); } else if (base.submodes[base.submodeID].HaveSubframeGain == 1) { num30 = bits.Unpack(1); num32 = (float)(num6 * Math.Exp((double)NbCodec.exc_gain_quant_scal1[num30])); } else { num32 = num6; } if (base.submodes[base.submodeID].Innovation != null) { base.submodes[base.submodeID].Innovation.Unquantify(base.innov, num31, base.subframeSize, bits); } num = num31; while (num < (num31 + base.subframeSize)) { base.innov[num] *= num32; num++; } if (base.submodeID == 1) { float num33 = num7; num = 0; while (num < base.subframeSize) { base.excBuf[es + num] = 0f; num++; } while (base.voc_offset < base.subframeSize) { if (base.voc_offset >= 0) { base.excBuf[es + base.voc_offset] = (float)Math.Sqrt((double)(1f * num4)); } base.voc_offset += num4; } base.voc_offset -= base.subframeSize; num33 = 0.5f + (2f * (num33 - 0.6f)); if (num33 < 0f) { num33 = 0f; } if (num33 > 1f) { num33 = 1f; } num = 0; while (num < base.subframeSize) { float num34 = base.excBuf[es + num]; base.excBuf[es + num] = ((((((0.8f * num33) * base.excBuf[es + num]) * num6) + (((0.6f * num33) * base.voc_m1) * num6)) + ((0.5f * num33) * base.innov[num31 + num])) - ((0.5f * num33) * base.voc_m2)) + ((1f - num33) * base.innov[num31 + num]); base.voc_m1 = num34; base.voc_m2 = base.innov[num31 + num]; base.voc_mean = (0.95f * base.voc_mean) + (0.05f * base.excBuf[es + num]); base.excBuf[es + num] -= base.voc_mean; num++; } } else { num = 0; while (num < base.subframeSize) { base.excBuf[es + num] += base.innov[num31 + num]; num++; } } if (base.submodes[base.submodeID].DoubleCodebook != 0) { num = 0; while (num < base.subframeSize) { this.innov2[num] = 0f; num++; } base.submodes[base.submodeID].Innovation.Unquantify(this.innov2, 0, base.subframeSize, bits); num = 0; while (num < base.subframeSize) { this.innov2[num] *= num32 * 0.4545454f; num++; } num = 0; while (num < base.subframeSize) { base.excBuf[es + num] += this.innov2[num]; num++; } } num = 0; while (num < base.subframeSize) { base.frmBuf[nsi + num] = base.excBuf[es + num]; num++; } if (this.enhanced && (base.submodes[base.submodeID].CombGain > 0f)) { base.filters.Comb_filter(base.excBuf, es, base.frmBuf, nsi, base.subframeSize, pitch, numArray, base.submodes[base.submodeID].CombGain); } if (this.enhanced) { Filters.Filter_mem2(base.frmBuf, nsi, base.awk2, base.awk1, base.subframeSize, base.lpcSize, base.mem_sp, base.lpcSize); Filters.Filter_mem2(base.frmBuf, nsi, base.awk3, base.interp_qlpc, base.subframeSize, base.lpcSize, base.mem_sp, 0); } else { num = 0; while (num < base.lpcSize) { base.mem_sp[base.lpcSize + num] = 0f; num++; } Filters.Iir_mem2(base.frmBuf, nsi, base.interp_qlpc, base.frmBuf, nsi, base.subframeSize, base.lpcSize, base.mem_sp); } } xout[0] = base.frmBuf[base.frmIdx] + (base.preemph * base.pre_mem); for (num = 1; num < base.frameSize; num++) { xout[num] = base.frmBuf[base.frmIdx + num] + (base.preemph * xout[num - 1]); } base.pre_mem = xout[base.frameSize - 1]; for (num = 0; num < base.lpcSize; num++) { base.old_qlsp[num] = base.qlsp[num]; } base.first = 0; this.count_lost = 0; this.last_pitch = num8; this.last_pitch_gain = 0.25f * num10; this.pitch_gain_buf[this.pitch_gain_buf_idx++] = this.last_pitch_gain; if (this.pitch_gain_buf_idx > 2) { this.pitch_gain_buf_idx = 0; } this.last_ol_gain = num6; return 0; } public int DecodeLost(float[] xout) { int num; float num3 = (float)Math.Exp((-0.04 * this.count_lost) * this.count_lost); float num4 = (this.pitch_gain_buf[0] < this.pitch_gain_buf[1]) ? ((this.pitch_gain_buf[1] < this.pitch_gain_buf[2]) ? this.pitch_gain_buf[1] : ((this.pitch_gain_buf[0] < this.pitch_gain_buf[2]) ? this.pitch_gain_buf[2] : this.pitch_gain_buf[0])) : ((this.pitch_gain_buf[2] < this.pitch_gain_buf[1]) ? this.pitch_gain_buf[1] : ((this.pitch_gain_buf[2] < this.pitch_gain_buf[0]) ? this.pitch_gain_buf[2] : this.pitch_gain_buf[0])); if (num4 < this.last_pitch_gain) { this.last_pitch_gain = num4; } float num2 = this.last_pitch_gain; if (num2 > 0.95f) { num2 = 0.95f; } num2 *= num3; Array.Copy(base.frmBuf, base.frameSize, base.frmBuf, 0, base.bufSize - base.frameSize); Array.Copy(base.excBuf, base.frameSize, base.excBuf, 0, base.bufSize - base.frameSize); for (int i = 0; i < base.nbSubframes; i++) { int num6 = base.subframeSize * i; int xs = base.frmIdx + num6; int num8 = base.excIdx + num6; if (this.enhanced) { float num10; float num11; float num9 = 0.9f; if (base.submodes[base.submodeID] != null) { num10 = base.submodes[base.submodeID].LpcEnhK1; num11 = base.submodes[base.submodeID].LpcEnhK2; } else { num10 = num11 = 0.7f; } float gamma = (1f - ((1f - (num9 * num10)) / (1f - (num9 * num11)))) / num9; Filters.Bw_lpc(num10, base.interp_qlpc, base.awk1, base.lpcSize); Filters.Bw_lpc(num11, base.interp_qlpc, base.awk2, base.lpcSize); Filters.Bw_lpc(gamma, base.interp_qlpc, base.awk3, base.lpcSize); } float num13 = 0f; num = 0; while (num < base.frameSize) { num13 += base.innov[num] * base.innov[num]; num++; } num13 = (float)Math.Sqrt((double)(num13 / ((float)base.frameSize))); num = 0; while (num < base.subframeSize) { base.excBuf[num8 + num] = (num2 * base.excBuf[(num8 + num) - this.last_pitch]) + ((((num3 * ((float)Math.Sqrt((double)(1f - num2)))) * 3f) * num13) * (((float)this.random.NextDouble()) - 0.5f)); num++; } num = 0; while (num < base.subframeSize) { base.frmBuf[xs + num] = base.excBuf[num8 + num]; num++; } if (this.enhanced) { Filters.Filter_mem2(base.frmBuf, xs, base.awk2, base.awk1, base.subframeSize, base.lpcSize, base.mem_sp, base.lpcSize); Filters.Filter_mem2(base.frmBuf, xs, base.awk3, base.interp_qlpc, base.subframeSize, base.lpcSize, base.mem_sp, 0); } else { num = 0; while (num < base.lpcSize) { base.mem_sp[base.lpcSize + num] = 0f; num++; } Filters.Iir_mem2(base.frmBuf, xs, base.interp_qlpc, base.frmBuf, xs, base.subframeSize, base.lpcSize, base.mem_sp); } } xout[0] = base.frmBuf[0] + (base.preemph * base.pre_mem); for (num = 1; num < base.frameSize; num++) { xout[num] = base.frmBuf[num] + (base.preemph * xout[num - 1]); } base.pre_mem = xout[base.frameSize - 1]; base.first = 0; this.count_lost++; this.pitch_gain_buf[this.pitch_gain_buf_idx++] = num2; if (this.pitch_gain_buf_idx > 2) { this.pitch_gain_buf_idx = 0; } return 0; } public virtual void DecodeStereo(float[] data, int frameSize) { this.stereo.Decode(data, frameSize); } protected override void Init(int frameSize, int subframeSize, int lpcSize, int bufSize) { base.Init(frameSize, subframeSize, lpcSize, bufSize); this.innov2 = new float[40]; this.count_lost = 0; this.last_pitch = 40; this.last_pitch_gain = 0f; this.pitch_gain_buf = new float[3]; this.pitch_gain_buf_idx = 0; this.last_ol_gain = 0f; } public bool Dtx { get { return (base.dtx_enabled != 0); } } public virtual bool PerceptualEnhancement { get { return this.enhanced; } set { this.enhanced = value; } } } }