/// <summary>Decode the given input bits.</summary> /// <remarks>Decode the given input bits.</remarks> /// <param name="bits">- Speex bits buffer.</param> /// <param name="out">- the decoded mono audio frame.</param> /// <returns>1 if a terminator was found, 0 if not.</returns> /// <exception cref="java.io.StreamCorruptedException"> /// If there is an error detected in the /// data stream. /// </exception> public virtual int decode(org.xiph.speex.Bits bits, float[] @out) { int i; int sub; int pitch; int ol_pitch = 0; int m; float[] pitch_gain = new float[3]; float ol_gain = 0.0f; float 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 == null) { decodeLost(@out); return 0; } do { if (bits.unpack(1) != 0) { //Wideband m = bits.unpack(org.xiph.speex.SbCodec.SB_SUBMODE_BITS); int advance = org.xiph.speex.SbCodec.SB_FRAME_SIZE[m]; if (advance < 0) { throw new java.io.StreamCorruptedException("Invalid sideband mode encountered (1st sideband): " + m); } //return -2; advance -= (org.xiph.speex.SbCodec.SB_SUBMODE_BITS + 1); bits.advance(advance); if (bits.unpack(1) != 0) { m = bits.unpack(org.xiph.speex.SbCodec.SB_SUBMODE_BITS); advance = org.xiph.speex.SbCodec.SB_FRAME_SIZE[m]; if (advance < 0) { throw new java.io.StreamCorruptedException("Invalid sideband mode encountered. (2nd sideband): " + m); } //return -2; advance -= (org.xiph.speex.SbCodec.SB_SUBMODE_BITS + 1); bits.advance(advance); if (bits.unpack(1) != 0) { throw new java.io.StreamCorruptedException("More than two sideband layers found"); } } } //return -2; //*/ m = bits.unpack(NB_SUBMODE_BITS); if (m == 15) { return 1; } else { if (m == 14) { inband.speexInbandRequest(bits); } else { if (m == 13) { inband.userInbandRequest(bits); } else { if (m > 8) { throw new java.io.StreamCorruptedException("Invalid mode encountered: " + m); } } } } } while (m > 8); //return -2; submodeID = m; } System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize - frameSize); System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize - frameSize); if (submodes[submodeID] == null) { org.xiph.speex.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)System.Math.Sqrt(innov_gain / frameSize); for (i = excIdx; i < excIdx + frameSize; i++) { excBuf[i] = 3 * innov_gain * (random.nextFloat() - .5f); } first = 1; org.xiph.speex.Filters.iir_mem2(excBuf, excIdx, lpc, frmBuf, frmIdx, frameSize, lpcSize , mem_sp); @out[0] = frmBuf[frmIdx] + preemph * pre_mem; for (i = 1; i < frameSize; i++) { @out[i] = frmBuf[frmIdx + i] + preemph * @out[i - 1]; } pre_mem = @out[frameSize - 1]; count_lost = 0; return 0; } submodes[submodeID].lsqQuant.unquant(qlsp, lpcSize, bits); if (count_lost != 0) { float lsp_dist = 0; float fact; for (i = 0; i < lpcSize; i++) { lsp_dist += System.Math.Abs(old_qlsp[i] - qlsp[i]); } fact = (float)(.6 * System.Math.Exp(-.2 * lsp_dist)); for (i = 0; i < 2 * lpcSize; i++) { mem_sp[i] *= fact; } } if (first != 0 || count_lost != 0) { for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } } if (submodes[submodeID].lbr_pitch != -1) { ol_pitch = min_pitch + bits.unpack(7); } if (submodes[submodeID].forced_pitch_gain != 0) { int quant = bits.unpack(4); ol_pitch_coef = 0.066667f * quant; } int qe = bits.unpack(5); ol_gain = (float)System.Math.Exp(qe / 3.5); if (submodeID == 1) { int extra = bits.unpack(4); if (extra == 15) { dtx_enabled = 1; } else { dtx_enabled = 0; } } if (submodeID > 1) { dtx_enabled = 0; } for (sub = 0; sub < nbSubframes; sub++) { int offset; int spIdx; int extIdx; float tmp; offset = subframeSize * sub; spIdx = frmIdx + offset; extIdx = excIdx + offset; tmp = (1.0f + sub) / nbSubframes; for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; } org.xiph.speex.Lsp.enforce_margin(interp_qlsp, lpcSize, .002f); for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); } m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); if (enhanced) { float r = .9f; float k1; float k2; float k3; k1 = submodes[submodeID].lpc_enh_k1; k2 = submodes[submodeID].lpc_enh_k2; k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r; org.xiph.speex.Filters.bw_lpc(k1, interp_qlpc, awk1, lpcSize); org.xiph.speex.Filters.bw_lpc(k2, interp_qlpc, awk2, lpcSize); org.xiph.speex.Filters.bw_lpc(k3, interp_qlpc, awk3, lpcSize); } tmp = 1; pi_gain[sub] = 0; for (i = 0; i <= lpcSize; i++) { pi_gain[sub] += tmp * interp_qlpc[i]; tmp = -tmp; } for (i = 0; i < subframeSize; i++) { excBuf[extIdx + i] = 0; } int pit_min; int pit_max; if (submodes[submodeID].lbr_pitch != -1) { int margin = submodes[submodeID].lbr_pitch; 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 = submodes[submodeID].ltp.unquant(excBuf, extIdx, pit_min, ol_pitch_coef, subframeSize , pitch_gain, bits, count_lost, offset, last_pitch_gain); if (count_lost != 0 && ol_gain < last_ol_gain) { float fact = ol_gain / (last_ol_gain + 1); for (i = 0; i < subframeSize; i++) { excBuf[excIdx + i] *= fact; } } tmp = System.Math.Abs(pitch_gain[0] + pitch_gain[1] + pitch_gain[2]); tmp = System.Math.Abs(pitch_gain[1]); if (pitch_gain[0] > 0) { tmp += pitch_gain[0]; } else { tmp -= (float)(.5 * pitch_gain[0]); } if (pitch_gain[2] > 0) { tmp += pitch_gain[2]; } else { tmp -= (float)(.5 * pitch_gain[0]); } pitch_average += tmp; if (tmp > best_pitch_gain) { best_pitch = pitch; best_pitch_gain = tmp; } int q_energy; int ivi = sub * subframeSize; float ener; for (i = ivi; i < ivi + subframeSize; i++) { innov[i] = 0.0f; } if (submodes[submodeID].have_subframe_gain == 3) { q_energy = bits.unpack(3); ener = (float)(ol_gain * System.Math.Exp(exc_gain_quant_scal3[q_energy])); } else { if (submodes[submodeID].have_subframe_gain == 1) { q_energy = bits.unpack(1); ener = (float)(ol_gain * System.Math.Exp(exc_gain_quant_scal1[q_energy])); } else { ener = ol_gain; } } if (submodes[submodeID].innovation != null) { submodes[submodeID].innovation.unquant(innov, ivi, subframeSize, bits); } for (i = ivi; i < ivi + subframeSize; i++) { innov[i] *= ener; } 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)System.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]; } } if (submodes[submodeID].double_codebook != 0) { for (i = 0; i < subframeSize; i++) { innov2[i] = 0; } submodes[submodeID].innovation.unquant(innov2, 0, subframeSize, bits); for (i = 0; i < subframeSize; i++) { innov2[i] *= (float)(ener * (1 / 2.2)); } for (i = 0; i < subframeSize; i++) { excBuf[extIdx + i] += innov2[i]; } } for (i = 0; i < subframeSize; i++) { frmBuf[spIdx + i] = excBuf[extIdx + i]; } if (enhanced && submodes[submodeID].comb_gain > 0) { filters.comb_filter(excBuf, extIdx, frmBuf, spIdx, subframeSize, pitch, pitch_gain , submodes[submodeID].comb_gain); } if (enhanced) { org.xiph.speex.Filters.filter_mem2(frmBuf, spIdx, awk2, awk1, subframeSize, lpcSize , mem_sp, lpcSize); org.xiph.speex.Filters.filter_mem2(frmBuf, spIdx, awk3, interp_qlpc, subframeSize , lpcSize, mem_sp, 0); } else { for (i = 0; i < lpcSize; i++) { mem_sp[lpcSize + i] = 0; } org.xiph.speex.Filters.iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf, spIdx, subframeSize , lpcSize, mem_sp); } } @out[0] = frmBuf[frmIdx] + preemph * pre_mem; for (i = 1; i < frameSize; i++) { @out[i] = frmBuf[frmIdx + i] + preemph * @out[i - 1]; } pre_mem = @out[frameSize - 1]; for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } 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) { pitch_gain_buf_idx = 0; } last_ol_gain = ol_gain; return 0; }
/// <summary>Callback handler for intensity stereo info</summary> /// <param name="bits">- Speex bits buffer.</param> public virtual void init(org.xiph.speex.Bits bits) { float sign = 1; int tmp; if (bits.unpack(1) != 0) { sign = -1; } tmp = bits.unpack(5); balance = (float)System.Math.Exp(sign * .25 * tmp); tmp = bits.unpack(2); e_ratio = e_ratio_quant[tmp]; }
/// <summary>Codebook Search Unquantification (Split Shape).</summary> /// <remarks>Codebook Search Unquantification (Split Shape).</remarks> /// <param name="exc">- excitation array.</param> /// <param name="es">- position in excitation array.</param> /// <param name="nsf">- number of samples in subframe.</param> /// <param name="bits">- Speex bits buffer.</param> public override sealed void unquant(float[] exc, int es, int nsf, org.xiph.speex.Bits bits) { int i; int j; for (i = 0; i < nb_subvect; i++) { if (have_sign != 0) { signs[i] = bits.unpack(1); } else { signs[i] = 0; } ind[i] = bits.unpack(shape_bits); } for (i = 0; i < nb_subvect; i++) { float s = 1.0f; if (signs[i] != 0) { s = -1.0f; } for (j = 0; j < subvect_size; j++) { exc[es + subvect_size * i + j] += s * 0.03125f * (float)shape_cb[ind[i] * subvect_size + j]; } } }
/// <summary>Decode the given input bits.</summary> /// <remarks>Decode the given input bits.</remarks> /// <param name="bits">- Speex bits buffer.</param> /// <param name="out">- the decoded mono audio frame.</param> /// <returns>1 if a terminator was found, 0 if not.</returns> /// <exception cref="java.io.StreamCorruptedException"> /// If there is an error detected in the /// data stream. /// </exception> public virtual int decode(org.xiph.speex.Bits bits, float[] @out) { int i; int sub; int wideband; int ret; float[] low_pi_gain; float[] low_exc; float[] low_innov; ret = lowdec.decode(bits, x0d); if (ret != 0) { return ret; } bool dtx = lowdec.getDtx(); if (bits == null) { decodeLost(@out, dtx); return 0; } wideband = bits.peek(); if (wideband != 0) { wideband = bits.unpack(1); submodeID = bits.unpack(3); } else { submodeID = 0; } for (i = 0; i < frameSize; i++) { excBuf[i] = 0; } if (submodes[submodeID] == null) { if (dtx) { decodeLost(@out, true); return 0; } for (i = 0; i < frameSize; i++) { excBuf[i] = VERY_SMALL; } first = 1; org.xiph.speex.Filters.iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, frameSize, lpcSize, mem_sp); filters.fir_mem_up(x0d, h0, y0, fullFrameSize, QMF_ORDER, g0_mem); filters.fir_mem_up(high, h1, y1, fullFrameSize, QMF_ORDER, g1_mem); for (i = 0; i < fullFrameSize; i++) { @out[i] = 2 * (y0[i] - y1[i]); } return 0; } low_pi_gain = lowdec.getPiGain(); low_exc = lowdec.getExc(); low_innov = lowdec.getInnov(); submodes[submodeID].lsqQuant.unquant(qlsp, lpcSize, bits); if (first != 0) { for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } } for (sub = 0; sub < nbSubframes; sub++) { float tmp; float filter_ratio; float el = 0.0f; float rl = 0.0f; float rh = 0.0f; int subIdx = subframeSize * sub; tmp = (1.0f + sub) / nbSubframes; for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; } org.xiph.speex.Lsp.enforce_margin(interp_qlsp, lpcSize, .05f); for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)System.Math.Cos(interp_qlsp[i]); } m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); if (enhanced) { float k1; float k2; float k3; k1 = submodes[submodeID].lpc_enh_k1; k2 = submodes[submodeID].lpc_enh_k2; k3 = k1 - k2; org.xiph.speex.Filters.bw_lpc(k1, interp_qlpc, awk1, lpcSize); org.xiph.speex.Filters.bw_lpc(k2, interp_qlpc, awk2, lpcSize); org.xiph.speex.Filters.bw_lpc(k3, interp_qlpc, awk3, lpcSize); } tmp = 1; pi_gain[sub] = 0; for (i = 0; i <= lpcSize; i++) { rh += tmp * interp_qlpc[i]; tmp = -tmp; pi_gain[sub] += interp_qlpc[i]; } rl = low_pi_gain[sub]; rl = 1 / (System.Math.Abs(rl) + .01f); rh = 1 / (System.Math.Abs(rh) + .01f); filter_ratio = System.Math.Abs(.01f + rh) / (.01f + System.Math.Abs(rl)); for (i = subIdx; i < subIdx + subframeSize; i++) { excBuf[i] = 0; } if (submodes[submodeID].innovation == null) { float g; int quant; quant = bits.unpack(5); g = (float)System.Math.Exp(((double)quant - 10) / 8.0); g /= filter_ratio; for (i = subIdx; i < subIdx + subframeSize; i++) { excBuf[i] = foldingGain * g * low_innov[i]; } } else { float gc; float scale; int qgc = bits.unpack(4); for (i = subIdx; i < subIdx + subframeSize; i++) { el += low_exc[i] * low_exc[i]; } gc = (float)System.Math.Exp((1 / 3.7f) * qgc - 2); scale = gc * (float)System.Math.Sqrt(1 + el) / filter_ratio; submodes[submodeID].innovation.unquant(excBuf, subIdx, subframeSize, bits); for (i = subIdx; i < subIdx + subframeSize; i++) { excBuf[i] *= scale; } if (submodes[submodeID].double_codebook != 0) { for (i = 0; i < subframeSize; i++) { innov2[i] = 0; } submodes[submodeID].innovation.unquant(innov2, 0, subframeSize, bits); for (i = 0; i < subframeSize; i++) { innov2[i] *= scale * (1 / 2.5f); } for (i = 0; i < subframeSize; i++) { excBuf[subIdx + i] += innov2[i]; } } } for (i = subIdx; i < subIdx + subframeSize; i++) { high[i] = excBuf[i]; } if (enhanced) { org.xiph.speex.Filters.filter_mem2(high, subIdx, awk2, awk1, subframeSize, lpcSize , mem_sp, lpcSize); org.xiph.speex.Filters.filter_mem2(high, subIdx, awk3, interp_qlpc, subframeSize, lpcSize, mem_sp, 0); } else { for (i = 0; i < lpcSize; i++) { mem_sp[lpcSize + i] = 0; } org.xiph.speex.Filters.iir_mem2(high, subIdx, interp_qlpc, high, subIdx, subframeSize , lpcSize, mem_sp); } } filters.fir_mem_up(x0d, h0, y0, fullFrameSize, QMF_ORDER, g0_mem); filters.fir_mem_up(high, h1, y1, fullFrameSize, QMF_ORDER, g1_mem); for (i = 0; i < fullFrameSize; i++) { @out[i] = 2 * (y0[i] - y1[i]); } for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } first = 0; return 0; }
/// <summary>Long Term Prediction Unquantification (3Tap).</summary> /// <remarks>Long Term Prediction Unquantification (3Tap).</remarks> /// <param name="exc">- Excitation</param> /// <param name="es">- Excitation offset</param> /// <param name="start">- Smallest pitch value allowed</param> /// <param name="pitch_coef">- Voicing (pitch) coefficient</param> /// <param name="nsf">- Number of samples in subframe</param> /// <param name="gain_val"></param> /// <param name="bits">- Speex bits buffer.</param> /// <param name="count_lost"></param> /// <param name="subframe_offset"></param> /// <param name="last_pitch_gain"></param> /// <returns>pitch</returns> public override sealed int unquant(float[] exc, int es, int start, float pitch_coef , int nsf, float[] gain_val, org.xiph.speex.Bits bits, int count_lost, int subframe_offset , float last_pitch_gain) { int i; int pitch; int gain_index; pitch = bits.unpack(pitch_bits); pitch += start; gain_index = bits.unpack(gain_bits); gain[0] = 0.015625f * (float)gain_cdbk[gain_index * 3] + .5f; gain[1] = 0.015625f * (float)gain_cdbk[gain_index * 3 + 1] + .5f; gain[2] = 0.015625f * (float)gain_cdbk[gain_index * 3 + 2] + .5f; if (count_lost != 0 && pitch > subframe_offset) { float gain_sum = System.Math.Abs(gain[1]); float tmp = count_lost < 4 ? last_pitch_gain : 0.4f * last_pitch_gain; if (tmp > .95f) { tmp = .95f; } if (gain[0] > 0) { gain_sum += gain[0]; } else { gain_sum -= .5f * gain[0]; } if (gain[2] > 0) { gain_sum += gain[2]; } else { gain_sum -= .5f * gain[0]; } if (gain_sum > tmp) { float fact = tmp / gain_sum; for (i = 0; i < 3; i++) { gain[i] *= fact; } } } gain_val[0] = gain[0]; gain_val[1] = gain[1]; gain_val[2] = gain[2]; for (i = 0; i < 3; i++) { int j; int pp = pitch + 1 - i; int tmp1; int tmp2; tmp1 = nsf; if (tmp1 > pp) { tmp1 = pp; } tmp2 = nsf; if (tmp2 > pp + pitch) { tmp2 = pp + pitch; } for (j = 0; j < tmp1; j++) { e[i][j] = exc[es + j - pp]; } for (j = tmp1; j < tmp2; j++) { e[i][j] = exc[es + j - pp - pitch]; } for (j = tmp2; j < nsf; j++) { e[i][j] = 0; } } for (i = 0; i < nsf; i++) { exc[es + i] = org.xiph.speex.NbCodec.VERY_SMALL + gain[0] * e[2][i] + gain[1] * e [1][i] + gain[2] * e[0][i]; } return pitch; }
/// <summary> /// Read the next 6 bits from the buffer, and using the value read and the /// given codebook, rebuild LSP table. /// </summary> /// <remarks> /// Read the next 6 bits from the buffer, and using the value read and the /// given codebook, rebuild LSP table. /// </remarks> /// <param name="lsp"></param> /// <param name="tab"></param> /// <param name="bits">- Speex bits buffer.</param> /// <param name="k"></param> /// <param name="ti"></param> /// <param name="li"></param> protected virtual void unpackPlus(float[] lsp, int[] tab, org.xiph.speex.Bits bits , float k, int ti, int li) { int id = bits.unpack(6); for (int i = 0; i < ti; i++) { lsp[i + li] += k * (float)tab[id * ti + i]; } }
/// <summary>Speex in-band request (submode=14).</summary> /// <remarks>Speex in-band request (submode=14).</remarks> /// <param name="bits">- Speex bits buffer.</param> /// <exception cref="java.io.StreamCorruptedException">If stream seems corrupted.</exception> public virtual void speexInbandRequest(org.xiph.speex.Bits bits) { int code = bits.unpack(4); switch (code) { case 0: { // asks the decoder to set perceptual enhancment off (0) or on (1) bits.advance(1); break; } case 1: { // asks (if 1) the encoder to be less "aggressive" due to high packet loss bits.advance(1); break; } case 2: { // asks the encoder to switch to mode N bits.advance(4); break; } case 3: { // asks the encoder to switch to mode N for low-band bits.advance(4); break; } case 4: { // asks the encoder to switch to mode N for high-band bits.advance(4); break; } case 5: { // asks the encoder to switch to quality N for VBR bits.advance(4); break; } case 6: { // request acknowledgement (0=no, 1=all, 2=only for inband data) bits.advance(4); break; } case 7: { // asks the encoder to set CBR(0), VAD(1), DTX(3), VBR(5), VBR+DTX(7) bits.advance(4); break; } case 8: { // transmit (8-bit) character to the other end bits.advance(8); break; } case 9: { // intensity stereo information // setup the stereo decoder; to skip: tmp = bits.unpack(8); break; stereo.init(bits); // read 8 bits break; } case 10: { // announce maximum bit-rate acceptable (N in byets/second) bits.advance(16); break; } case 11: { // reserved bits.advance(16); break; } case 12: { // Acknowledge receiving packet N bits.advance(32); break; } case 13: { // reserved bits.advance(32); break; } case 14: { // reserved bits.advance(64); break; } case 15: { // reserved bits.advance(64); break; } default: { break; } } }
/// <summary>User in-band request (submode=13).</summary> /// <remarks>User in-band request (submode=13).</remarks> /// <param name="bits">- Speex bits buffer.</param> /// <exception cref="java.io.StreamCorruptedException">If stream seems corrupted.</exception> public virtual void userInbandRequest(org.xiph.speex.Bits bits) { int req_size = bits.unpack(4); bits.advance(5 + 8 * req_size); }