/// <summary> /// Encode the given input signal. /// </summary> /// <param name="bits">Speex bits buffer.</param> /// <param name="vin">the raw mono audio frame to encode</param> /// <returns>1 if successful.</returns> public int Encode(Bits bits, float[] vin) { int i; float[] mem, innov, syn_resp; float[] low_pi_gain, low_exc, low_innov; int dtx; /* Compute the two sub-bands by filtering with h0 and h1*/ Filters.qmf_decomp(vin, h0, x0d, x1d, fullFrameSize, QMF_ORDER, h0_mem); /* Encode the narrowband part*/ lowenc.Encode(bits, x0d); /* High-band buffering / sync with low band */ for (i = 0; i < windowSize - frameSize; i++) { high[i] = high[frameSize + i]; } for (i = 0; i < frameSize; i++) { high[windowSize - frameSize + i] = x1d[i]; } Array.Copy(excBuf, frameSize, excBuf, 0, bufSize - frameSize); low_pi_gain = lowenc.PitchGain; low_exc = lowenc.Excitation; low_innov = lowenc.Innovation; int low_mode = lowenc.Mode; if (low_mode == 0) { dtx = 1; } else { dtx = 0; } /* Start encoding the high-band */ for (i = 0; i < windowSize; i++) { buf[i] = high[i] * window[i]; } /* Compute auto-correlation */ Lpc.autocorr(buf, autocorr, lpcSize + 1, windowSize); autocorr[0] += 1; /* prevents NANs */ autocorr[0] *= lpc_floor; /* Noise floor in auto-correlation domain */ /* Lag windowing: equivalent to filtering in the power-spectrum domain */ for (i = 0; i < lpcSize + 1; i++) { autocorr[i] *= lagWindow[i]; } /* Levinson-Durbin */ Lpc.wld(lpc, autocorr, rc, lpcSize); // tmperr Array.Copy(lpc, 0, lpc, 1, lpcSize); lpc[0] = 1; /* LPC to LSPs (x-domain) transform */ int roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 15, 0.2f); if (roots != lpcSize) { roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 11, 0.02f); if (roots != lpcSize) { /*If we can't find all LSP's, do some damage control and use a flat filter*/ for (i = 0; i < lpcSize; i++) { lsp[i] = (float)Math.Cos(Math.PI * ((float)(i + 1)) / (lpcSize + 1)); } } } /* x-domain to angle domain*/ for (i = 0; i < lpcSize; i++) { lsp[i] = (float)Math.Acos(lsp[i]); } float lsp_dist = 0; for (i = 0; i < lpcSize; i++) { lsp_dist += (old_lsp[i] - lsp[i]) * (old_lsp[i] - lsp[i]); } /*VBR stuff*/ if ((vbr_enabled != 0 || vad_enabled != 0) && dtx == 0) { float e_low = 0, e_high = 0; float ratio; if (abr_enabled != 0) { float qual_change = 0; if (abr_drift2 * abr_drift > 0) { /* Only adapt if long-term and short-term drift are the same sign */ qual_change = -.00001f * abr_drift / (1 + abr_count); if (qual_change > .1f) { qual_change = .1f; } if (qual_change < -.1f) { qual_change = -.1f; } } vbr_quality += qual_change; if (vbr_quality > 10) { vbr_quality = 10; } if (vbr_quality < 0) { vbr_quality = 0; } } for (i = 0; i < frameSize; i++) { e_low += x0d[i] * x0d[i]; e_high += high[i] * high[i]; } ratio = (float)Math.Log((1 + e_high) / (1 + e_low)); relative_quality = lowenc.RelativeQuality; if (ratio < -4) { ratio = -4; } if (ratio > 2) { ratio = 2; } /*if (ratio>-2)*/ if (vbr_enabled != 0) { int modeid; modeid = nb_modes - 1; relative_quality += 1.0f * (ratio + 2f); if (relative_quality < -1) { relative_quality = -1; } while (modeid != 0) { int v1; float thresh; v1 = (int)Math.Floor(vbr_quality); if (v1 == 10) { thresh = NSpeex.Vbr.hb_thresh[modeid][v1]; } else { thresh = (vbr_quality - v1) * NSpeex.Vbr.hb_thresh[modeid][v1 + 1] + (1 + v1 - vbr_quality) * NSpeex.Vbr.hb_thresh[modeid][v1]; } if (relative_quality >= thresh) { break; } modeid--; } Mode = modeid; if (abr_enabled != 0) { int bitrate = BitRate; abr_drift += (bitrate - abr_enabled); abr_drift2 = .95f * abr_drift2 + .05f * (bitrate - abr_enabled); abr_count += 1.0f; } } else { /* VAD only */ int modeid; if (relative_quality < 2.0) { modeid = 1; } else { modeid = submodeSelect; } /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ submodeID = modeid; } } bits.Pack(1, 1); if (dtx != 0) { bits.Pack(0, SB_SUBMODE_BITS); } else { bits.Pack(submodeID, SB_SUBMODE_BITS); } /* If null mode (no transmission), just set a couple things to zero*/ if (dtx != 0 || submodes[submodeID] == null) { for (i = 0; i < frameSize; i++) { excBuf[excIdx + i] = swBuf[i] = VERY_SMALL; } for (i = 0; i < lpcSize; i++) { mem_sw[i] = 0; } first = 1; /* Final signal synthesis from excitation */ Filters.iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, subframeSize, lpcSize, mem_sp); /* Reconstruct the original */ 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++) { vin[i] = 2 * (y0[i] - y1[i]); } if (dtx != 0) { return(0); } else { return(1); } } /* LSP quantization */ submodes[submodeID].lsqQuant.quant(lsp, qlsp, lpcSize, bits); if (first != 0) { for (i = 0; i < lpcSize; i++) { old_lsp[i] = lsp[i]; } for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } } mem = new float[lpcSize]; syn_resp = new float[subframeSize]; innov = new float[subframeSize]; for (int sub = 0; sub < nbSubframes; sub++) { float tmp, filter_ratio; int exc, sp, sw, resp; int offset; float rl, rh, eh = 0, el = 0; int fold; offset = subframeSize * sub; sp = offset; exc = excIdx + offset; resp = offset; sw = offset; /* LSP interpolation (quantized and unquantized) */ tmp = (1.0f + sub) / nbSubframes; for (i = 0; i < lpcSize; i++) { interp_lsp[i] = (1 - tmp) * old_lsp[i] + tmp * lsp[i]; } for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; } Lsp.enforce_margin(interp_lsp, lpcSize, .05f); Lsp.enforce_margin(interp_qlsp, lpcSize, .05f); /* Compute interpolated LPCs (quantized and unquantized) */ for (i = 0; i < lpcSize; i++) { interp_lsp[i] = (float)Math.Cos(interp_lsp[i]); } for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)Math.Cos(interp_qlsp[i]); } m_lsp.lsp2lpc(interp_lsp, interp_lpc, lpcSize); m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); Filters.bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize); Filters.bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize); /* Compute mid-band (4000 Hz for wideband) response of low-band and high-band * filters */ rl = rh = 0; 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 / (Math.Abs(rl) + .01f); rh = 1 / (Math.Abs(rh) + .01f); /* Compute ratio, will help predict the gain */ filter_ratio = Math.Abs(.01f + rh) / (.01f + Math.Abs(rl)); fold = filter_ratio < 5 ? 1 : 0; /*printf ("filter_ratio %f\n", filter_ratio);*/ fold = 0; /* Compute "real excitation" */ Filters.fir_mem2(high, sp, interp_qlpc, excBuf, exc, subframeSize, lpcSize, mem_sp2); /* Compute energy of low-band and high-band excitation */ for (i = 0; i < subframeSize; i++) { eh += excBuf[exc + i] * excBuf[exc + i]; } if (submodes[submodeID].innovation == null) { float g; /*speex_bits_pack(bits, 1, 1);*/ for (i = 0; i < subframeSize; i++) { el += low_innov[offset + i] * low_innov[offset + i]; } /* Gain to use if we want to use the low-band excitation for high-band */ g = eh / (.01f + el); g = (float)Math.Sqrt(g); g *= filter_ratio; int quant = (int)Math.Floor(.5 + 10 + 8.0 * Math.Log((g + .0001))); /*speex_warning_int("tata", quant);*/ if (quant < 0) { quant = 0; } if (quant > 31) { quant = 31; } bits.Pack(quant, 5); g = (float)(.1 * Math.Exp(quant / 9.4)); g /= filter_ratio; } else { float gc, scale, scale_1; for (i = 0; i < subframeSize; i++) { el += low_exc[offset + i] * low_exc[offset + i]; } gc = (float)(Math.Sqrt(1 + eh) * filter_ratio / Math.Sqrt((1 + el) * subframeSize)); { int qgc = (int)Math.Floor(.5 + 3.7 * (Math.Log(gc) + 2)); if (qgc < 0) { qgc = 0; } if (qgc > 15) { qgc = 15; } bits.Pack(qgc, 4); gc = (float)Math.Exp((1 / 3.7) * qgc - 2); } scale = gc * (float)Math.Sqrt(1 + el) / filter_ratio; scale_1 = 1 / scale; for (i = 0; i < subframeSize; i++) { excBuf[exc + i] = 0; } excBuf[exc] = 1; Filters.syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, subframeSize, lpcSize); /* Reset excitation */ for (i = 0; i < subframeSize; i++) { excBuf[exc + i] = 0; } /* Compute zero response (ringing) of A(z/g1) / ( A(z/g2) * Aq(z) ) */ for (i = 0; i < lpcSize; i++) { mem[i] = mem_sp[i]; } Filters.iir_mem2(excBuf, exc, interp_qlpc, excBuf, exc, subframeSize, lpcSize, mem); for (i = 0; i < lpcSize; i++) { mem[i] = mem_sw[i]; } Filters.filter_mem2(excBuf, exc, bw_lpc1, bw_lpc2, res, resp, subframeSize, lpcSize, mem, 0); /* Compute weighted signal */ for (i = 0; i < lpcSize; i++) { mem[i] = mem_sw[i]; } Filters.filter_mem2(high, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem, 0); /* Compute target signal */ for (i = 0; i < subframeSize; i++) { target[i] = swBuf[sw + i] - res[resp + i]; } for (i = 0; i < subframeSize; i++) { excBuf[exc + i] = 0; } for (i = 0; i < subframeSize; i++) { target[i] *= scale_1; } /* Reset excitation */ for (i = 0; i < subframeSize; i++) { innov[i] = 0; } /*print_vec(target, st->subframeSize, "\ntarget");*/ submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2, lpcSize, subframeSize, innov, 0, syn_resp, bits, (complexity + 1) >> 1); /*print_vec(target, st->subframeSize, "after");*/ for (i = 0; i < subframeSize; i++) { excBuf[exc + i] += innov[i] * scale; } if (submodes[submodeID].double_codebook != 0) { float[] innov2 = new float[subframeSize]; for (i = 0; i < subframeSize; i++) { innov2[i] = 0; } for (i = 0; i < subframeSize; i++) { target[i] *= 2.5f; } submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2, lpcSize, subframeSize, innov2, 0, syn_resp, bits, (complexity + 1) >> 1); for (i = 0; i < subframeSize; i++) { innov2[i] *= scale * (1f / 2.5f); } for (i = 0; i < subframeSize; i++) { excBuf[exc + i] += innov2[i]; } } } /*Keep the previous memory*/ for (i = 0; i < lpcSize; i++) { mem[i] = mem_sp[i]; } /* Final signal synthesis from excitation */ Filters.iir_mem2(excBuf, exc, interp_qlpc, high, sp, subframeSize, lpcSize, mem_sp); /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ Filters.filter_mem2(high, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem_sw, 0); } //#ifndef RELEASE /* Reconstruct the original */ 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++) { vin[i] = 2 * (y0[i] - y1[i]); } //#endif for (i = 0; i < lpcSize; i++) { old_lsp[i] = lsp[i]; } for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } first = 0; return(1); }
/// <summary> /// Decode the given input bits. /// </summary> /// <param name="bits">Speex bits buffer.</param> /// <param name="vout">the decoded mono audio frame.</param> /// <returns> /// 1 if a terminator was found, 0 if not. /// </returns> public int Decode(Bits bits, float[] vout) { int i, sub, wideband, ret; float[] low_pi_gain, low_exc, low_innov; /* Decode the low-band */ ret = lowdec.Decode(bits, x0d); if (ret != 0) { return(ret); } bool dtx = lowdec.Dtx; if (bits == null) { decodeLost(vout, dtx); return(0); } /* Check "wideband bit" */ wideband = bits.Peek(); if (wideband != 0) { /*Regular wideband frame, read the submode*/ wideband = bits.UnPack(1); submodeID = bits.UnPack(3); } else { /* was a narrowband frame, set "null submode"*/ submodeID = 0; } for (i = 0; i < frameSize; i++) { excBuf[i] = 0; } if (submodes[submodeID] == null) { if (dtx) { decodeLost(vout, true); return(0); } for (i = 0; i < frameSize; i++) { excBuf[i] = VERY_SMALL; } first = 1; Filters.iir_mem2(excBuf, excIdx, interp_qlpc, high, 0, frameSize, lpcSize, mem_sp); filters.fir_mem_up(x0d, Codebook.h0, y0, fullFrameSize, QMF_ORDER, g0_mem); filters.fir_mem_up(high, Codebook.h1, y1, fullFrameSize, QMF_ORDER, g1_mem); for (i = 0; i < fullFrameSize; i++) { vout[i] = 2 * (y0[i] - y1[i]); } return(0); } low_pi_gain = lowdec.PitchGain; low_exc = lowdec.Excitation; low_innov = lowdec.Innovation; 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, filter_ratio, el = 0.0f, rl = 0.0f, rh = 0.0f; int subIdx = subframeSize * sub; /* LSP interpolation */ tmp = (1.0f + sub) / nbSubframes; for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; } Lsp.enforce_margin(interp_qlsp, lpcSize, .05f); /* LSPs to x-domain */ for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)Math.Cos(interp_qlsp[i]); } /* LSP to LPC */ m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); if (enhanced) { float k1, k2, k3; k1 = submodes[submodeID].lpc_enh_k1; k2 = submodes[submodeID].lpc_enh_k2; k3 = k1 - k2; Filters.bw_lpc(k1, interp_qlpc, awk1, lpcSize); Filters.bw_lpc(k2, interp_qlpc, awk2, lpcSize); Filters.bw_lpc(k3, interp_qlpc, awk3, lpcSize); } /* Calculate reponse ratio between low & high filter in band middle (4000 Hz) */ 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 / (Math.Abs(rl) + .01f); rh = 1 / (Math.Abs(rh) + .01f); filter_ratio = Math.Abs(.01f + rh) / (.01f + Math.Abs(rl)); /* reset excitation buffer */ 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)Math.Exp(((double)quant - 10) / 8.0); g /= filter_ratio; /* High-band excitation using the low-band excitation and a gain */ for (i = subIdx; i < subIdx + subframeSize; i++) { excBuf[i] = foldingGain * g * low_innov[i]; } } else { float gc, scale; int qgc = bits.UnPack(4); for (i = subIdx; i < subIdx + subframeSize; i++) { el += low_exc[i] * low_exc[i]; } gc = (float)Math.Exp((1 / 3.7f) * qgc - 2); scale = gc * (float)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) { /* Use enhanced LPC filter */ Filters.filter_mem2(high, subIdx, awk2, awk1, subframeSize, lpcSize, mem_sp, lpcSize); Filters.filter_mem2(high, subIdx, awk3, interp_qlpc, subframeSize, lpcSize, mem_sp, 0); } else { /* Use regular filter */ for (i = 0; i < lpcSize; i++) { mem_sp[lpcSize + i] = 0; } Filters.iir_mem2(high, subIdx, interp_qlpc, high, subIdx, subframeSize, lpcSize, mem_sp); } } filters.fir_mem_up(x0d, Codebook.h0, y0, fullFrameSize, QMF_ORDER, g0_mem); filters.fir_mem_up(high, Codebook.h1, y1, fullFrameSize, QMF_ORDER, g1_mem); for (i = 0; i < fullFrameSize; i++) { vout[i] = 2 * (y0[i] - y1[i]); } for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } first = 0; return(0); }
public int Encode(Bits bits, float[] vin) { int i; float[] res, target, mem; float[] syn_resp; float[] orig; /* Copy new data in input buffer */ System.Array.Copy(frmBuf, frameSize, frmBuf, 0, bufSize - frameSize); frmBuf[bufSize - frameSize] = vin[0] - preemph * pre_mem; for (i = 1; i < frameSize; i++) { frmBuf[bufSize - frameSize + i] = vin[i] - preemph * vin[i - 1]; } pre_mem = vin[frameSize - 1]; /* Move signals 1 frame towards the past */ System.Array.Copy(exc2Buf, frameSize, exc2Buf, 0, bufSize - frameSize); System.Array.Copy(excBuf, frameSize, excBuf, 0, bufSize - frameSize); System.Array.Copy(swBuf, frameSize, swBuf, 0, bufSize - frameSize); /* Window for analysis */ for (i = 0; i < windowSize; i++) { buf2[i] = frmBuf[i + frmIdx] * window[i]; } /* Compute auto-correlation */ Lpc.autocorr(buf2, autocorr, lpcSize + 1, windowSize); autocorr[0] += 10; /* prevents NANs */ autocorr[0] *= lpc_floor; /* Noise floor in auto-correlation domain */ /* Lag windowing: equivalent to filtering in the power-spectrum domain */ for (i = 0; i < lpcSize + 1; i++) { autocorr[i] *= lagWindow[i]; } /* Levinson-Durbin */ Lpc.wld(lpc, autocorr, rc, lpcSize); // tmperr System.Array.Copy(lpc, 0, lpc, 1, lpcSize); lpc[0] = 1; /* LPC to LSPs (x-domain) transform */ int roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 15, 0.2f); /* Check if we found all the roots */ if (roots == lpcSize) { /* LSP x-domain to angle domain*/ for (i = 0; i < lpcSize; i++) { lsp[i] = (float)Math.Acos(lsp[i]); } } else { /* Search again if we can afford it */ if (complexity > 1) { roots = Lsp.lpc2lsp(lpc, lpcSize, lsp, 11, 0.05f); } if (roots == lpcSize) { /* LSP x-domain to angle domain*/ for (i = 0; i < lpcSize; i++) { lsp[i] = (float)Math.Acos(lsp[i]); } } else { /*If we can't find all LSP's, do some damage control and use previous filter*/ for (i = 0; i < lpcSize; i++) { lsp[i] = old_lsp[i]; } } } float lsp_dist = 0; for (i = 0; i < lpcSize; i++) { lsp_dist += (old_lsp[i] - lsp[i]) * (old_lsp[i] - lsp[i]); } /* Whole frame analysis (open-loop estimation of pitch and excitation gain) */ float ol_gain; int ol_pitch; float ol_pitch_coef; { if (first != 0) { for (i = 0; i < lpcSize; i++) { interp_lsp[i] = lsp[i]; } } else { for (i = 0; i < lpcSize; i++) { interp_lsp[i] = .375f * old_lsp[i] + .625f * lsp[i]; } } Lsp.enforce_margin(interp_lsp, lpcSize, .002f); /* Compute interpolated LPCs (unquantized) for whole frame*/ for (i = 0; i < lpcSize; i++) { interp_lsp[i] = (float)Math.Cos(interp_lsp[i]); } m_lsp.lsp2lpc(interp_lsp, interp_lpc, lpcSize); /*Open-loop pitch*/ if (submodes[submodeID] == null || vbr_enabled != 0 || vad_enabled != 0 || submodes[submodeID].forced_pitch_gain != 0 || submodes[submodeID].lbr_pitch != -1) { int[] nol_pitch = new int[6]; float[] nol_pitch_coef = new float[6]; Filters.bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize); Filters.bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize); Filters.filter_mem2(frmBuf, frmIdx, bw_lpc1, bw_lpc2, swBuf, swIdx, frameSize, lpcSize, mem_sw_whole, 0); Ltp.open_loop_nbest_pitch(swBuf, swIdx, min_pitch, max_pitch, frameSize, nol_pitch, nol_pitch_coef, 6); ol_pitch = nol_pitch[0]; ol_pitch_coef = nol_pitch_coef[0]; /*Try to remove pitch multiples*/ for (i = 1; i < 6; i++) { if ((nol_pitch_coef[i] > .85 * ol_pitch_coef) && (Math.Abs(nol_pitch[i] - ol_pitch / 2.0) <= 1 || Math.Abs(nol_pitch[i] - ol_pitch / 3.0) <= 1 || Math.Abs(nol_pitch[i] - ol_pitch / 4.0) <= 1 || Math.Abs(nol_pitch[i] - ol_pitch / 5.0) <= 1)) { /*ol_pitch_coef=nol_pitch_coef[i];*/ ol_pitch = nol_pitch[i]; } } /*if (ol_pitch>50) * ol_pitch/=2;*/ /*ol_pitch_coef = sqrt(ol_pitch_coef);*/ } else { ol_pitch = 0; ol_pitch_coef = 0; } /*Compute "real" excitation*/ Filters.fir_mem2(frmBuf, frmIdx, interp_lpc, excBuf, excIdx, frameSize, lpcSize, mem_exc); /* Compute open-loop excitation gain */ ol_gain = 0; for (i = 0; i < frameSize; i++) { ol_gain += excBuf[excIdx + i] * excBuf[excIdx + i]; } ol_gain = (float)Math.Sqrt(1 + ol_gain / frameSize); } /*VBR stuff*/ if (vbr != null && (vbr_enabled != 0 || vad_enabled != 0)) { if (abr_enabled != 0) { float qual_change = 0; if (abr_drift2 * abr_drift > 0) { /* Only adapt if long-term and short-term drift are the same sign */ qual_change = -.00001f * abr_drift / (1 + abr_count); if (qual_change > .05f) { qual_change = .05f; } if (qual_change < -.05f) { qual_change = -.05f; } } vbr_quality += qual_change; if (vbr_quality > 10) { vbr_quality = 10; } if (vbr_quality < 0) { vbr_quality = 0; } } relative_quality = vbr.analysis(vin, frameSize, ol_pitch, ol_pitch_coef); /*if (delta_qual<0)*/ /* delta_qual*=.1*(3+st->vbr_quality);*/ if (vbr_enabled != 0) { int mode; int choice = 0; float min_diff = 100; mode = 8; while (mode > 0) { int v1; float thresh; v1 = (int)Math.Floor(vbr_quality); if (v1 == 10) { thresh = NSpeex.Vbr.nb_thresh[mode][v1]; } else { thresh = (vbr_quality - v1) * NSpeex.Vbr.nb_thresh[mode][v1 + 1] + (1 + v1 - vbr_quality) * NSpeex.Vbr.nb_thresh[mode][v1]; } if (relative_quality > thresh && relative_quality - thresh < min_diff) { choice = mode; min_diff = relative_quality - thresh; } mode--; } mode = choice; if (mode == 0) { if (dtx_count == 0 || lsp_dist > .05 || dtx_enabled == 0 || dtx_count > 20) { mode = 1; dtx_count = 1; } else { mode = 0; dtx_count++; } } else { dtx_count = 0; } Mode = mode; if (abr_enabled != 0) { int bitrate; bitrate = BitRate; abr_drift += (bitrate - abr_enabled); abr_drift2 = .95f * abr_drift2 + .05f * (bitrate - abr_enabled); abr_count += 1.0f; } } else { /*VAD only case*/ int mode; if (relative_quality < 2) { if (dtx_count == 0 || lsp_dist > .05 || dtx_enabled == 0 || dtx_count > 20) { dtx_count = 1; mode = 1; } else { mode = 0; dtx_count++; } } else { dtx_count = 0; mode = submodeSelect; } /*speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);*/ submodeID = mode; } } else { relative_quality = -1; } /* First, transmit a zero for narrowband */ bits.Pack(0, 1); /* Transmit the sub-mode we use for this frame */ bits.Pack(submodeID, NB_SUBMODE_BITS); /* If null mode (no transmission), just set a couple things to zero*/ if (submodes[submodeID] == null) { for (i = 0; i < frameSize; i++) { excBuf[excIdx + i] = exc2Buf[exc2Idx + i] = swBuf[swIdx + i] = VERY_SMALL; } for (i = 0; i < lpcSize; i++) { mem_sw[i] = 0; } first = 1; bounded_pitch = 1; /* Final signal synthesis from excitation */ Filters.iir_mem2(excBuf, excIdx, interp_qlpc, frmBuf, frmIdx, frameSize, lpcSize, mem_sp); vin[0] = frmBuf[frmIdx] + preemph * pre_mem2; for (i = 1; i < frameSize; i++) { vin[i] = frmBuf[frmIdx = i] + preemph * vin[i - 1]; } pre_mem2 = vin[frameSize - 1]; return(0); } /* LSP Quantization */ if (first != 0) { for (i = 0; i < lpcSize; i++) { old_lsp[i] = lsp[i]; } } /*Quantize LSPs*/ //#if 1 /*0 for unquantized*/ submodes[submodeID].lsqQuant.quant(lsp, qlsp, lpcSize, bits); //#else // for (i=0;i<lpcSize;i++) // qlsp[i]=lsp[i]; //#endif /*If we use low bit-rate pitch mode, transmit open-loop pitch*/ if (submodes[submodeID].lbr_pitch != -1) { bits.Pack(ol_pitch - min_pitch, 7); } if (submodes[submodeID].forced_pitch_gain != 0) { int quant; quant = (int)Math.Floor(.5 + 15 * ol_pitch_coef); if (quant > 15) { quant = 15; } if (quant < 0) { quant = 0; } bits.Pack(quant, 4); ol_pitch_coef = (float)0.066667 * quant; } /*Quantize and transmit open-loop excitation gain*/ { int qe = (int)(Math.Floor(0.5 + 3.5 * Math.Log(ol_gain))); if (qe < 0) { qe = 0; } if (qe > 31) { qe = 31; } ol_gain = (float)Math.Exp(qe / 3.5); bits.Pack(qe, 5); } /* Special case for first frame */ if (first != 0) { for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } } /* Filter response */ res = new float[subframeSize]; /* Target signal */ target = new float[subframeSize]; syn_resp = new float[subframeSize]; mem = new float[lpcSize]; orig = new float[frameSize]; for (i = 0; i < frameSize; i++) { orig[i] = frmBuf[frmIdx + i]; } /* Loop on sub-frames */ for (int sub = 0; sub < nbSubframes; sub++) { float tmp; int offset; int sp, sw, exc, exc2; int pitchval; /* Offset relative to start of frame */ offset = subframeSize * sub; /* Original signal */ sp = frmIdx + offset; /* Excitation */ exc = excIdx + offset; /* Weighted signal */ sw = swIdx + offset; exc2 = exc2Idx + offset; /* LSP interpolation (quantized and unquantized) */ tmp = (float)(1.0 + sub) / nbSubframes; for (i = 0; i < lpcSize; i++) { interp_lsp[i] = (1 - tmp) * old_lsp[i] + tmp * lsp[i]; } for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (1 - tmp) * old_qlsp[i] + tmp * qlsp[i]; } /* Make sure the filters are stable */ Lsp.enforce_margin(interp_lsp, lpcSize, .002f); Lsp.enforce_margin(interp_qlsp, lpcSize, .002f); /* Compute interpolated LPCs (quantized and unquantized) */ for (i = 0; i < lpcSize; i++) { interp_lsp[i] = (float)Math.Cos(interp_lsp[i]); } m_lsp.lsp2lpc(interp_lsp, interp_lpc, lpcSize); for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)Math.Cos(interp_qlsp[i]); } m_lsp.lsp2lpc(interp_qlsp, interp_qlpc, lpcSize); /* Compute analysis filter gain at w=pi (for use in SB-CELP) */ tmp = 1; pi_gain[sub] = 0; for (i = 0; i <= lpcSize; i++) { pi_gain[sub] += tmp * interp_qlpc[i]; tmp = -tmp; } /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */ Filters.bw_lpc(gamma1, interp_lpc, bw_lpc1, lpcSize); if (gamma2 >= 0) { Filters.bw_lpc(gamma2, interp_lpc, bw_lpc2, lpcSize); } else { bw_lpc2[0] = 1; bw_lpc2[1] = -preemph; for (i = 2; i <= lpcSize; i++) { bw_lpc2[i] = 0; } } /* Compute impulse response of A(z/g1) / ( A(z)*A(z/g2) )*/ for (i = 0; i < subframeSize; i++) { excBuf[exc + i] = 0; } excBuf[exc] = 1; Filters.syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, bw_lpc2, syn_resp, subframeSize, lpcSize); /* Reset excitation */ for (i = 0; i < subframeSize; i++) { excBuf[exc + i] = 0; } for (i = 0; i < subframeSize; i++) { exc2Buf[exc2 + i] = 0; } /* Compute zero response of A(z/g1) / ( A(z/g2) * A(z) ) */ for (i = 0; i < lpcSize; i++) { mem[i] = mem_sp[i]; } Filters.iir_mem2(excBuf, exc, interp_qlpc, excBuf, exc, subframeSize, lpcSize, mem); for (i = 0; i < lpcSize; i++) { mem[i] = mem_sw[i]; } Filters.filter_mem2(excBuf, exc, bw_lpc1, bw_lpc2, res, 0, subframeSize, lpcSize, mem, 0); /* Compute weighted signal */ for (i = 0; i < lpcSize; i++) { mem[i] = mem_sw[i]; } Filters.filter_mem2(frmBuf, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem, 0); /* Compute target signal */ for (i = 0; i < subframeSize; i++) { target[i] = swBuf[sw + i] - res[i]; } for (i = 0; i < subframeSize; i++) { excBuf[exc + i] = exc2Buf[exc2 + i] = 0; } /* If we have a long-term predictor (otherwise, something's wrong) */ // if (submodes[submodeID].ltp.quant) // { int pit_min, pit_max; /* Long-term prediction */ if (submodes[submodeID].lbr_pitch != -1) { /* Low bit-rate pitch handling */ int margin; margin = submodes[submodeID].lbr_pitch; if (margin != 0) { if (ol_pitch < min_pitch + margin - 1) { ol_pitch = min_pitch + margin - 1; } if (ol_pitch > max_pitch - margin) { ol_pitch = max_pitch - margin; } pit_min = ol_pitch - margin + 1; pit_max = ol_pitch + margin; } else { pit_min = pit_max = ol_pitch; } } else { pit_min = min_pitch; pit_max = max_pitch; } /* Force pitch to use only the current frame if needed */ if (bounded_pitch != 0 && pit_max > offset) { pit_max = offset; } /* Perform pitch search */ pitchval = submodes[submodeID].ltp.Quant(target, swBuf, sw, interp_qlpc, bw_lpc1, bw_lpc2, excBuf, exc, pit_min, pit_max, ol_pitch_coef, lpcSize, subframeSize, bits, exc2Buf, exc2, syn_resp, complexity); pitch[sub] = pitchval; // } else { // speex_error ("No pitch prediction, what's wrong"); // } /* Update target for adaptive codebook contribution */ Filters.syn_percep_zero(excBuf, exc, interp_qlpc, bw_lpc1, bw_lpc2, res, subframeSize, lpcSize); for (i = 0; i < subframeSize; i++) { target[i] -= res[i]; } /* Quantization of innovation */ { int innovptr; float ener = 0, ener_1; innovptr = sub * subframeSize; for (i = 0; i < subframeSize; i++) { innov[innovptr + i] = 0; } Filters.residue_percep_zero(target, 0, interp_qlpc, bw_lpc1, bw_lpc2, buf2, subframeSize, lpcSize); for (i = 0; i < subframeSize; i++) { ener += buf2[i] * buf2[i]; } ener = (float)Math.Sqrt(.1f + ener / subframeSize); /*for (i=0;i<subframeSize;i++) * System.out.print(buf2[i]/ener + "\t"); */ ener /= ol_gain; /* Calculate gain correction for the sub-frame (if any) */ if (submodes[submodeID].have_subframe_gain != 0) { int qe; ener = (float)Math.Log(ener); if (submodes[submodeID].have_subframe_gain == 3) { qe = VQ.index(ener, exc_gain_quant_scal3, 8); bits.Pack(qe, 3); ener = exc_gain_quant_scal3[qe]; } else { qe = VQ.index(ener, exc_gain_quant_scal1, 2); bits.Pack(qe, 1); ener = exc_gain_quant_scal1[qe]; } ener = (float)Math.Exp(ener); } else { ener = 1; } ener *= ol_gain; /*System.out.println(ener + " " + ol_gain);*/ ener_1 = 1 / ener; /* Normalize innovation */ for (i = 0; i < subframeSize; i++) { target[i] *= ener_1; } /* Quantize innovation */ // if (submodes[submodeID].innovation != null) // { /* Codebook search */ submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2, lpcSize, subframeSize, innov, innovptr, syn_resp, bits, complexity); /* De-normalize innovation and update excitation */ for (i = 0; i < subframeSize; i++) { innov[innovptr + i] *= ener; } for (i = 0; i < subframeSize; i++) { excBuf[exc + i] += innov[innovptr + i]; } // } else { // speex_error("No fixed codebook"); // } /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */ if (submodes[submodeID].double_codebook != 0) { float[] innov2 = new float[subframeSize]; // for (i=0;i<subframeSize;i++) // innov2[i]=0; for (i = 0; i < subframeSize; i++) { target[i] *= 2.2f; } submodes[submodeID].innovation.Quant(target, interp_qlpc, bw_lpc1, bw_lpc2, lpcSize, subframeSize, innov2, 0, syn_resp, bits, complexity); for (i = 0; i < subframeSize; i++) { innov2[i] *= ener * (1f / 2.2f); } for (i = 0; i < subframeSize; i++) { excBuf[exc + i] += innov2[i]; } } for (i = 0; i < subframeSize; i++) { target[i] *= ener; } } /*Keep the previous memory*/ for (i = 0; i < lpcSize; i++) { mem[i] = mem_sp[i]; } /* Final signal synthesis from excitation */ Filters.iir_mem2(excBuf, exc, interp_qlpc, frmBuf, sp, subframeSize, lpcSize, mem_sp); /* Compute weighted signal again, from synthesized speech (not sure it's the right thing) */ Filters.filter_mem2(frmBuf, sp, bw_lpc1, bw_lpc2, swBuf, sw, subframeSize, lpcSize, mem_sw, 0); for (i = 0; i < subframeSize; i++) { exc2Buf[exc2 + i] = excBuf[exc + i]; } } /* Store the LSPs for interpolation in the next frame */ if (submodeID >= 1) { for (i = 0; i < lpcSize; i++) { old_lsp[i] = lsp[i]; } for (i = 0; i < lpcSize; i++) { old_qlsp[i] = qlsp[i]; } } if (submodeID == 1) { if (dtx_count != 0) { bits.Pack(15, 4); } else { bits.Pack(0, 4); } } /* The next frame will not be the first (Duh!) */ first = 0; { float ener = 0, err = 0; float snr; for (i = 0; i < frameSize; i++) { ener += frmBuf[frmIdx + i] * frmBuf[frmIdx + i]; err += (frmBuf[frmIdx + i] - orig[i]) * (frmBuf[frmIdx + i] - orig[i]); } snr = (float)(10 * Math.Log((ener + 1) / (err + 1))); /*System.out.println("Frame result: SNR="+snr+" E="+ener+" Err="+err+"\r\n");*/ } /* Replace input by synthesized speech */ vin[0] = frmBuf[frmIdx] + preemph * pre_mem2; for (i = 1; i < frameSize; i++) { vin[i] = frmBuf[frmIdx + i] + preemph * vin[i - 1]; } pre_mem2 = vin[frameSize - 1]; if (submodes[submodeID].innovation is NoiseSearch || submodeID == 0) { bounded_pitch = 1; } else { bounded_pitch = 0; } return(1); }
/// <summary> /// Decode the given input bits. /// </summary> /// <param name="bits">Speex bits buffer.</param> /// <param name="vout">the decoded mono audio frame.</param> /// <returns>1 if a terminator was found, 0 if not.</returns> public int Decode(Bits bits, float[] vout) { 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 == null) { decodeLost(vout); return(0); } do { if (bits.UnPack(1) != 0) { m = bits.UnPack(SbCodec.SB_SUBMODE_BITS); int advance = SbCodec.SB_FRAME_SIZE[m]; if (advance < 0) { throw new Exception("Invalid sideband mode encountered (1st sideband): " + m); } advance -= (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(SbCodec.SB_SUBMODE_BITS); advance = SbCodec.SB_FRAME_SIZE[m]; if (advance < 0) { throw new Exception("Invalid sideband mode encountered. (2nd sideband): " + m); //return -2; } advance -= (SbCodec.SB_SUBMODE_BITS + 1); bits.Advance(advance); if (bits.UnPack(1) != 0) { /* Sanity check */ throw new Exception("More than two sideband layers found"); //return -2; } } } m = bits.UnPack(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 Exception("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 (submodes[submodeID] == null) { 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] = 3 * innov_gain * ((float)random.NextDouble() - .5f); } first = 1; /* Final signal synthesis from excitation */ Filters.iir_mem2(excBuf, excIdx, lpc, frmBuf, frmIdx, frameSize, lpcSize, mem_sp); vout[0] = frmBuf[frmIdx] + preemph * pre_mem; for (i = 1; i < frameSize; i++) { vout[i] = frmBuf[frmIdx + i] + preemph * vout[i - 1]; } pre_mem = vout[frameSize - 1]; count_lost = 0; return(0); } /* Unquantize LSPs */ submodes[submodeID].lsqQuant.unquant(qlsp, lpcSize, bits); 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)(.6 * Math.Exp(-.2 * 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].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; } /* Get global excitation gain */ int qe = bits.UnPack(5); ol_gain = (float)Math.Exp(qe / 3.5); /* 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 */ Lsp.enforce_margin(interp_qlsp, lpcSize, .002f); /* Compute interpolated LPCs (unquantized) */ for (i = 0; i < lpcSize; i++) { interp_qlsp[i] = (float)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].lpc_enh_k1; k2 = submodes[submodeID].lpc_enh_k2; k3 = (1 - (1 - r * k1) / (1 - r * k2)) / r; Filters.bw_lpc(k1, interp_qlpc, awk1, lpcSize); Filters.bw_lpc(k2, interp_qlpc, awk2, lpcSize); 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].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 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 = ol_gain / (last_ol_gain + 1); for (i = 0; i < subframeSize; i++) { excBuf[excIdx + i] *= fact; } } 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].have_subframe_gain == 3) { q_energy = bits.UnPack(3); ener = (float)(ol_gain * 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 * Math.Exp(exc_gain_quant_scal1[q_energy])); } else { ener = ol_gain; } if (submodes[submodeID].innovation != null) { /* Fixed codebook contribution */ submodes[submodeID].innovation.UnQuant(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].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] *= ener * (1f / 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].comb_gain > 0) { filters.comb_filter(excBuf, extIdx, frmBuf, spIdx, subframeSize, pitch, pitch_gain, submodes[submodeID].comb_gain); } if (enhanced) { /* Use enhanced LPC filter */ Filters.filter_mem2(frmBuf, spIdx, awk2, awk1, subframeSize, lpcSize, mem_sp, lpcSize); 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; } Filters.iir_mem2(frmBuf, spIdx, interp_qlpc, frmBuf, spIdx, subframeSize, lpcSize, mem_sp); } } /*Copy output signal*/ vout[0] = frmBuf[frmIdx] + preemph * pre_mem; for (i = 1; i < frameSize; i++) { vout[i] = frmBuf[frmIdx + i] + preemph * vout[i - 1]; } pre_mem = vout[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); }