public virtual int Decode(Bits bits, float[] xout) { int num = 0; float[] array = new float[3]; float num2 = 0f; int num3 = 40; float num4 = 0f; float num5 = 0f; if (bits == null && this.dtx_enabled != 0) { this.submodeID = 0; } else { if (bits == null) { this.DecodeLost(xout); return(0); } while (bits.BitsRemaining() >= 5) { int num6; if (bits.Unpack(1) != 0) { num6 = bits.Unpack(3); int num7 = SbCodec.SB_FRAME_SIZE[num6]; if (num7 < 0) { throw new InvalidFormatException("Invalid sideband mode encountered (1st sideband): " + num6); } num7 -= 4; bits.Advance(num7); if (bits.Unpack(1) != 0) { num6 = bits.Unpack(3); num7 = SbCodec.SB_FRAME_SIZE[num6]; if (num7 < 0) { throw new InvalidFormatException("Invalid sideband mode encountered. (2nd sideband): " + num6); } num7 -= 4; bits.Advance(num7); if (bits.Unpack(1) != 0) { throw new InvalidFormatException("More than two sideband layers found"); } } } if (bits.BitsRemaining() < 4) { return(1); } num6 = bits.Unpack(4); if (num6 == 15) { return(1); } if (num6 == 14) { this.inband.SpeexInbandRequest(bits); } else if (num6 == 13) { this.inband.UserInbandRequest(bits); } else if (num6 > 8) { throw new InvalidFormatException("Invalid mode encountered: " + num6); } if (num6 <= 8) { this.submodeID = num6; goto IL_199; } } return(-1); } IL_199: Array.Copy(this.frmBuf, this.frameSize, this.frmBuf, 0, this.bufSize - this.frameSize); Array.Copy(this.excBuf, this.frameSize, this.excBuf, 0, this.bufSize - this.frameSize); if (this.submodes[this.submodeID] == null) { Filters.Bw_lpc(0.93f, this.interp_qlpc, this.lpc, 10); float num8 = 0f; for (int i = 0; i < this.frameSize; i++) { num8 += this.innov[i] * this.innov[i]; } num8 = (float)Math.Sqrt((double)(num8 / (float)this.frameSize)); for (int i = this.excIdx; i < this.excIdx + this.frameSize; i++) { this.excBuf[i] = (float)((double)(3f * num8) * (this.random.NextDouble() - 0.5)); } this.first = 1; Filters.Iir_mem2(this.excBuf, this.excIdx, this.lpc, this.frmBuf, this.frmIdx, this.frameSize, this.lpcSize, this.mem_sp); xout[0] = this.frmBuf[this.frmIdx] + this.preemph * this.pre_mem; for (int i = 1; i < this.frameSize; i++) { xout[i] = this.frmBuf[this.frmIdx + i] + this.preemph * xout[i - 1]; } this.pre_mem = xout[this.frameSize - 1]; this.count_lost = 0; return(0); } this.submodes[this.submodeID].LsqQuant.Unquant(this.qlsp, this.lpcSize, bits); if (this.count_lost != 0) { float num9 = 0f; for (int i = 0; i < this.lpcSize; i++) { num9 += Math.Abs(this.old_qlsp[i] - this.qlsp[i]); } float num10 = (float)(0.6 * Math.Exp(-0.2 * (double)num9)); for (int i = 0; i < 2 * this.lpcSize; i++) { this.mem_sp[i] *= num10; } } if (this.first != 0 || this.count_lost != 0) { for (int i = 0; i < this.lpcSize; i++) { this.old_qlsp[i] = this.qlsp[i]; } } if (this.submodes[this.submodeID].LbrPitch != -1) { num = this.min_pitch + bits.Unpack(7); } if (this.submodes[this.submodeID].ForcedPitchGain != 0) { int num11 = bits.Unpack(4); num2 = 0.066667f * (float)num11; } int num12 = bits.Unpack(5); float num13 = (float)Math.Exp((double)num12 / 3.5); if (this.submodeID == 1) { int num14 = bits.Unpack(4); if (num14 == 15) { this.dtx_enabled = 1; } else { this.dtx_enabled = 0; } } if (this.submodeID > 1) { this.dtx_enabled = 0; } for (int j = 0; j < this.nbSubframes; j++) { int num15 = this.subframeSize * j; int num16 = this.frmIdx + num15; int num17 = this.excIdx + num15; float num18 = (1f + (float)j) / (float)this.nbSubframes; for (int i = 0; i < this.lpcSize; i++) { this.interp_qlsp[i] = (1f - num18) * this.old_qlsp[i] + num18 * this.qlsp[i]; } Lsp.Enforce_margin(this.interp_qlsp, this.lpcSize, 0.002f); for (int i = 0; i < this.lpcSize; i++) { this.interp_qlsp[i] = (float)Math.Cos((double)this.interp_qlsp[i]); } this.m_lsp.Lsp2lpc(this.interp_qlsp, this.interp_qlpc, this.lpcSize); if (this.enhanced) { float num19 = 0.9f; float lpcEnhK = this.submodes[this.submodeID].LpcEnhK1; float lpcEnhK2 = this.submodes[this.submodeID].LpcEnhK2; float gamma = (1f - (1f - num19 * lpcEnhK) / (1f - num19 * lpcEnhK2)) / num19; Filters.Bw_lpc(lpcEnhK, this.interp_qlpc, this.awk1, this.lpcSize); Filters.Bw_lpc(lpcEnhK2, this.interp_qlpc, this.awk2, this.lpcSize); Filters.Bw_lpc(gamma, this.interp_qlpc, this.awk3, this.lpcSize); } num18 = 1f; this.pi_gain[j] = 0f; for (int i = 0; i <= this.lpcSize; i++) { this.pi_gain[j] += num18 * this.interp_qlpc[i]; num18 = -num18; } for (int i = 0; i < this.subframeSize; i++) { this.excBuf[num17 + i] = 0f; } int num20; if (this.submodes[this.submodeID].LbrPitch != -1) { int lbrPitch = this.submodes[this.submodeID].LbrPitch; if (lbrPitch != 0) { num20 = num - lbrPitch + 1; if (num20 < this.min_pitch) { num20 = this.min_pitch; } int num21 = num + lbrPitch; if (num21 > this.max_pitch) { num21 = this.max_pitch; } } else { num20 = num; } } else { num20 = this.min_pitch; int num21 = this.max_pitch; } int num22 = this.submodes[this.submodeID].Ltp.Unquant(this.excBuf, num17, num20, num2, this.subframeSize, array, bits, this.count_lost, num15, this.last_pitch_gain); if (this.count_lost != 0 && num13 < this.last_ol_gain) { float num23 = num13 / (this.last_ol_gain + 1f); for (int i = 0; i < this.subframeSize; i++) { this.excBuf[this.excIdx + i] *= num23; } } num18 = Math.Abs(array[0] + array[1] + array[2]); num18 = Math.Abs(array[1]); if (array[0] > 0f) { num18 += array[0]; } else { num18 -= 0.5f * array[0]; } if (array[2] > 0f) { num18 += array[2]; } else { num18 -= 0.5f * array[0]; } num5 += num18; if (num18 > num4) { num3 = num22; num4 = num18; } int num24 = j * this.subframeSize; for (int i = num24; i < num24 + this.subframeSize; i++) { this.innov[i] = 0f; } float num26; if (this.submodes[this.submodeID].HaveSubframeGain == 3) { int num25 = bits.Unpack(3); num26 = (float)((double)num13 * Math.Exp((double)NbCodec.exc_gain_quant_scal3[num25])); } else if (this.submodes[this.submodeID].HaveSubframeGain == 1) { int num25 = bits.Unpack(1); num26 = (float)((double)num13 * Math.Exp((double)NbCodec.exc_gain_quant_scal1[num25])); } else { num26 = num13; } if (this.submodes[this.submodeID].Innovation != null) { this.submodes[this.submodeID].Innovation.Unquantify(this.innov, num24, this.subframeSize, bits); } for (int i = num24; i < num24 + this.subframeSize; i++) { this.innov[i] *= num26; } if (this.submodeID == 1) { float num27 = num2; for (int i = 0; i < this.subframeSize; i++) { this.excBuf[num17 + i] = 0f; } while (this.voc_offset < this.subframeSize) { if (this.voc_offset >= 0) { this.excBuf[num17 + this.voc_offset] = (float)Math.Sqrt((double)(1f * (float)num)); } this.voc_offset += num; } this.voc_offset -= this.subframeSize; num27 = 0.5f + 2f * (num27 - 0.6f); if (num27 < 0f) { num27 = 0f; } if (num27 > 1f) { num27 = 1f; } for (int i = 0; i < this.subframeSize; i++) { float voc_m = this.excBuf[num17 + i]; this.excBuf[num17 + i] = 0.8f * num27 * this.excBuf[num17 + i] * num13 + 0.6f * num27 * this.voc_m1 * num13 + 0.5f * num27 * this.innov[num24 + i] - 0.5f * num27 * this.voc_m2 + (1f - num27) * this.innov[num24 + i]; this.voc_m1 = voc_m; this.voc_m2 = this.innov[num24 + i]; this.voc_mean = 0.95f * this.voc_mean + 0.05f * this.excBuf[num17 + i]; this.excBuf[num17 + i] -= this.voc_mean; } } else { for (int i = 0; i < this.subframeSize; i++) { this.excBuf[num17 + i] += this.innov[num24 + i]; } } if (this.submodes[this.submodeID].DoubleCodebook != 0) { for (int i = 0; i < this.subframeSize; i++) { this.innov2[i] = 0f; } this.submodes[this.submodeID].Innovation.Unquantify(this.innov2, 0, this.subframeSize, bits); for (int i = 0; i < this.subframeSize; i++) { this.innov2[i] *= num26 * 0.454545438f; } for (int i = 0; i < this.subframeSize; i++) { this.excBuf[num17 + i] += this.innov2[i]; } } for (int i = 0; i < this.subframeSize; i++) { this.frmBuf[num16 + i] = this.excBuf[num17 + i]; } if (this.enhanced && this.submodes[this.submodeID].CombGain > 0f) { this.filters.Comb_filter(this.excBuf, num17, this.frmBuf, num16, this.subframeSize, num22, array, this.submodes[this.submodeID].CombGain); } if (this.enhanced) { Filters.Filter_mem2(this.frmBuf, num16, this.awk2, this.awk1, this.subframeSize, this.lpcSize, this.mem_sp, this.lpcSize); Filters.Filter_mem2(this.frmBuf, num16, this.awk3, this.interp_qlpc, this.subframeSize, this.lpcSize, this.mem_sp, 0); } else { for (int i = 0; i < this.lpcSize; i++) { this.mem_sp[this.lpcSize + i] = 0f; } Filters.Iir_mem2(this.frmBuf, num16, this.interp_qlpc, this.frmBuf, num16, this.subframeSize, this.lpcSize, this.mem_sp); } } xout[0] = this.frmBuf[this.frmIdx] + this.preemph * this.pre_mem; for (int i = 1; i < this.frameSize; i++) { xout[i] = this.frmBuf[this.frmIdx + i] + this.preemph * xout[i - 1]; } this.pre_mem = xout[this.frameSize - 1]; for (int i = 0; i < this.lpcSize; i++) { this.old_qlsp[i] = this.qlsp[i]; } this.first = 0; this.count_lost = 0; this.last_pitch = num3; this.last_pitch_gain = 0.25f * num5; 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 = num13; return(0); }
/// <summary> /// Decode the given input bits. /// </summary> /// <returns>1 if a terminator was found, 0 if not.</returns> /// <exception cref="InvalidFormatException">If there is an error detected in the data stream.</exception> public virtual int Decode(Bits bits, float[] xout) { int i, sub, pitch, ol_pitch = 0, m; float[] pitch_gain = new float[3]; float ol_gain = 0.0f, ol_pitch_coef = 0.0f; int best_pitch = 40; float best_pitch_gain = 0; float pitch_average = 0; if (bits == null && dtx_enabled != 0) { submodeID = 0; } else { /* * If bits is NULL, consider the packet to be lost (what could we do * anyway) */ if (bits == null) { DecodeLost(xout); return(0); } /* * Search for next narrowband block (handle requests, skip wideband * blocks) */ do { if (bits.BitsRemaining() < 5) { return(-1); } if (bits.Unpack(1) != 0) { /* * Skip wideband block (for * compatibility) */ // Wideband /* Get the sub-mode that was used */ m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS); int advance = NSpeex.SbCodec.SB_FRAME_SIZE[m]; if (advance < 0) { throw new InvalidFormatException( "Invalid sideband mode encountered (1st sideband): " + m); // return -2; } advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1); bits.Advance(advance); if (bits.Unpack(1) != 0) { /* * Skip ultra-wideband block * (for compatibility) */ /* Get the sub-mode that was used */ m = bits.Unpack(NSpeex.SbCodec.SB_SUBMODE_BITS); advance = NSpeex.SbCodec.SB_FRAME_SIZE[m]; if (advance < 0) { throw new InvalidFormatException( "Invalid sideband mode encountered. (2nd sideband): " + m); // return -2; } advance -= (NSpeex.SbCodec.SB_SUBMODE_BITS + 1); bits.Advance(advance); if (bits.Unpack(1) != 0) { /* Sanity check */ throw new InvalidFormatException( "More than two sideband layers found"); // return -2; } } // */ } if (bits.BitsRemaining() < 4) { return(1); } /* Get the sub-mode that was used */ m = bits.Unpack(NSpeex.NbCodec.NB_SUBMODE_BITS); if (m == 15) { /* We found a terminator */ return(1); } else if (m == 14) { /* Speex in-band request */ inband.SpeexInbandRequest(bits); } else if (m == 13) { /* User in-band request */ inband.UserInbandRequest(bits); } else if (m > 8) { /* Invalid mode */ throw new InvalidFormatException( "Invalid mode encountered: " + m); // return -2; } } while (m > 8); submodeID = m; } /* Shift all buffers by one frame */ System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize - frameSize); System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize - frameSize); /* If null mode (no transmission), just set a couple things to zero */ if (submodes[submodeID] == null) { NSpeex.Filters.Bw_lpc(.93f, interp_qlpc, lpc, 10); float innov_gain = 0; for (i = 0; i < frameSize; i++) { innov_gain += innov[i] * innov[i]; } innov_gain = (float)Math.Sqrt(innov_gain / frameSize); for (i = excIdx; i < excIdx + frameSize; i++) { excBuf[i] = (float)(3 * innov_gain * (random.NextDouble() - .5f)); } first = 1; /* Final signal synthesis from excitation */ NSpeex.Filters.Iir_mem2(excBuf, excIdx, lpc, frmBuf, frmIdx, frameSize, lpcSize, mem_sp); xout[0] = frmBuf[frmIdx] + preemph * pre_mem; for (i = 1; i < frameSize; i++) { xout[i] = frmBuf[frmIdx + i] + preemph * xout[i - 1]; } pre_mem = xout[frameSize - 1]; count_lost = 0; return(0); } /* Unquantize LSPs */ submodes[submodeID].LsqQuant.Unquant(qlsp, lpcSize, bits); /* Damp memory if a frame was lost and the LSP changed too much */ if (count_lost != 0) { float lsp_dist = 0, fact; for (i = 0; i < lpcSize; i++) { lsp_dist += Math.Abs(old_qlsp[i] - qlsp[i]); } fact = (float)(.6d * Math.Exp(-.2d * lsp_dist)); for (i = 0; i < 2 * lpcSize; i++) { mem_sp[i] *= fact; } } /* Handle first frame and lost-packet case */ if (first != 0 || count_lost != 0) { for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } } /* Get open-loop pitch estimation for low bit-rate pitch coding */ if (submodes[submodeID].LbrPitch != -1) { ol_pitch = min_pitch + bits.Unpack(7); } if (submodes[submodeID].ForcedPitchGain != 0) { int quant = bits.Unpack(4); ol_pitch_coef = 0.066667f * quant; } /* Get global excitation gain */ int qe = bits.Unpack(5); ol_gain = (float)Math.Exp(qe / 3.5d); /* unpacks unused dtx bits */ if (submodeID == 1) { int extra = bits.Unpack(4); if (extra == 15) { dtx_enabled = 1; } else { dtx_enabled = 0; } } if (submodeID > 1) { dtx_enabled = 0; } /* Loop on subframes */ for (sub = 0; sub < nbSubframes; sub++) { int offset, spIdx, extIdx; float tmp; /* Offset relative to start of frame */ offset = subframeSize * sub; /* Original signal */ spIdx = frmIdx + offset; /* Excitation */ extIdx = excIdx + offset; /* LSP interpolation (quantized and unquantized) */ tmp = (1.0f + sub) / nbSubframes; for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; } /* Make sure the LSP's are stable */ NSpeex.Lsp.Enforce_margin(interp_qlsp, lpcSize, .002f); /* Compute interpolated LPCs (unquantized) */ for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); } m_lsp.Lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); /* Compute enhanced synthesis filter */ if (enhanced) { float r = .9f; float k1, k2, k3; k1 = submodes[submodeID].LpcEnhK1; k2 = submodes[submodeID].LpcEnhK2; k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r; NSpeex.Filters.Bw_lpc(k1, interp_qlpc, awk1, lpcSize); NSpeex.Filters.Bw_lpc(k2, interp_qlpc, awk2, lpcSize); NSpeex.Filters.Bw_lpc(k3, interp_qlpc, awk3, lpcSize); } /* Compute analysis filter at w=pi */ tmp = 1; pi_gain[sub] = 0; for (i = 0; i <= lpcSize; i++) { pi_gain[sub] += tmp * interp_qlpc[i]; tmp = -tmp; } /* Reset excitation */ for (i = 0; i < subframeSize; i++) { excBuf[extIdx + i] = 0; } /* Adaptive codebook contribution */ int pit_min, pit_max; /* Handle pitch constraints if any */ if (submodes[submodeID].LbrPitch != -1) { int margin = submodes[submodeID].LbrPitch; if (margin != 0) { pit_min = ol_pitch - margin + 1; if (pit_min < min_pitch) { pit_min = min_pitch; } pit_max = ol_pitch + margin; if (pit_max > max_pitch) { pit_max = max_pitch; } } else { pit_min = pit_max = ol_pitch; } } else { pit_min = min_pitch; pit_max = max_pitch; } /* Pitch synthesis */ pitch = submodes[submodeID].Ltp.Unquant(excBuf, extIdx, pit_min, ol_pitch_coef, subframeSize, pitch_gain, bits, count_lost, offset, last_pitch_gain); /* If we had lost frames, check energy of last received frame */ if (count_lost != 0 && ol_gain < last_ol_gain) { float fact_0 = ol_gain / (last_ol_gain + 1); for (i = 0; i < subframeSize; i++) { excBuf[excIdx + i] *= fact_0; } } tmp = Math.Abs(pitch_gain[0] + pitch_gain[1] + pitch_gain[2]); tmp = Math.Abs(pitch_gain[1]); if (pitch_gain[0] > 0) { tmp += pitch_gain[0]; } else { tmp -= .5f * pitch_gain[0]; } if (pitch_gain[2] > 0) { tmp += pitch_gain[2]; } else { tmp -= .5f * pitch_gain[0]; } pitch_average += tmp; if (tmp > best_pitch_gain) { best_pitch = pitch; best_pitch_gain = tmp; } /* Unquantize the innovation */ int q_energy, ivi = sub * subframeSize; float ener; for (i = ivi; i < ivi + subframeSize; i++) { innov[i] = 0.0f; } /* Decode sub-frame gain correction */ if (submodes[submodeID].HaveSubframeGain == 3) { q_energy = bits.Unpack(3); ener = (float)(ol_gain * Math.Exp(NSpeex.NbCodec.exc_gain_quant_scal3[q_energy])); } else if (submodes[submodeID].HaveSubframeGain == 1) { q_energy = bits.Unpack(1); ener = (float)(ol_gain * Math.Exp(NSpeex.NbCodec.exc_gain_quant_scal1[q_energy])); } else { ener = ol_gain; } if (submodes[submodeID].Innovation != null) { /* Fixed codebook contribution */ submodes[submodeID].Innovation.Unquantify(innov, ivi, subframeSize, bits); } /* De-normalize innovation and update excitation */ for (i = ivi; i < ivi + subframeSize; i++) { innov[i] *= ener; } /* Vocoder mode */ if (submodeID == 1) { float g = ol_pitch_coef; for (i = 0; i < subframeSize; i++) { excBuf[extIdx + i] = 0; } while (voc_offset < subframeSize) { if (voc_offset >= 0) { excBuf[extIdx + voc_offset] = (float)Math.Sqrt(1.0f * ol_pitch); } voc_offset += ol_pitch; } voc_offset -= subframeSize; g = .5f + 2 * (g - .6f); if (g < 0) { g = 0; } if (g > 1) { g = 1; } for (i = 0; i < subframeSize; i++) { float itmp = excBuf[extIdx + i]; excBuf[extIdx + i] = .8f * g * excBuf[extIdx + i] * ol_gain + .6f * g * voc_m1 * ol_gain + .5f * g * innov[ivi + i] - .5f * g * voc_m2 + (1 - g) * innov[ivi + i]; voc_m1 = itmp; voc_m2 = innov[ivi + i]; voc_mean = .95f * voc_mean + .05f * excBuf[extIdx + i]; excBuf[extIdx + i] -= voc_mean; } } else { for (i = 0; i < subframeSize; i++) { excBuf[extIdx + i] += innov[ivi + i]; } } /* Decode second codebook (only for some modes) */ if (submodes[submodeID].DoubleCodebook != 0) { for (i = 0; i < subframeSize; i++) { innov2[i] = 0; } submodes[submodeID].Innovation.Unquantify(innov2, 0, subframeSize, bits); for (i = 0; i < subframeSize; i++) { innov2[i] *= ener * (1 / 2.2f); } for (i = 0; i < subframeSize; i++) { excBuf[extIdx + i] += innov2[i]; } } for (i = 0; i < subframeSize; i++) { frmBuf[spIdx + i] = excBuf[extIdx + i]; } /* Signal synthesis */ if (enhanced && submodes[submodeID].CombGain > 0) { filters.Comb_filter(excBuf, extIdx, frmBuf, spIdx, subframeSize, pitch, pitch_gain, submodes[submodeID].CombGain); } if (enhanced) { /* Use enhanced LPC filter */ NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk2, awk1, subframeSize, lpcSize, mem_sp, lpcSize); NSpeex.Filters.Filter_mem2(frmBuf, spIdx, awk3, interp_qlpc, subframeSize, lpcSize, mem_sp, 0); } else { /* Use regular filter */ for (i = 0; i < lpcSize; i++) { mem_sp[lpcSize + i] = 0; } NSpeex.Filters.Iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf, spIdx, subframeSize, lpcSize, mem_sp); } } /* Copy output signal */ xout[0] = frmBuf[frmIdx] + preemph * pre_mem; for (i = 1; i < frameSize; i++) { xout[i] = frmBuf[frmIdx + i] + preemph * xout[i - 1]; } pre_mem = xout[frameSize - 1]; /* Store the LSPs for interpolation in the next frame */ for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } /* The next frame will not be the first (Duh!) */ first = 0; count_lost = 0; last_pitch = best_pitch; last_pitch_gain = .25f * pitch_average; pitch_gain_buf[pitch_gain_buf_idx++] = last_pitch_gain; if (pitch_gain_buf_idx > 2) /* rollover */ { pitch_gain_buf_idx = 0; } last_ol_gain = ol_gain; return(0); }