void lsf_vq(struct melp_param *par) { register int16_t i, j, k; static BOOLEAN firstTime = TRUE; static int16_t qplsp[LPC_ORD]; /* Q15 */ const int16_t melp_cb_size[4] = { 256, 64, 32, 32 }; /* !!! (12/15/99) */ const int16_t res_cb_size[4] = { 256, 64, 64, 64 }; const int16_t melp_uv_cb_size[1] = { 512 }; int16_t uv_config; /* Bits of uv_config replace uv1, uv2 and cuv. */ int16_t *lsp[NF]; int32_t err, minErr, acc, bcc; /* !!! (12/15/99), Q11 */ int16_t temp1, temp2; int16_t lpc[LPC_ORD]; /* Q12 */ int16_t wgt[NF][LPC_ORD]; /* Q11 */ int16_t mwgt[2 * LPC_ORD]; /* Q11 */ int16_t bestlsp0[LPC_ORD], bestlsp1[LPC_ORD]; /* Q15 */ int16_t res[2 * LPC_ORD]; /* Q17 */ /* The original program declares lsp_cand[LSP_VQ_CAND][] and */ /* lsp_index_cand[LSP_VQ_CAND*LSP_VQ_STAGES] with LSP_VQ_CAND == 8. The */ /* program only uses up to LSP_INP_CAND == 5 and the declaration is */ /* modified. */ int16_t lsp_cand[LSP_INP_CAND][LPC_ORD]; /* Q15 */ int16_t lsp_index_cand[LSP_INP_CAND * LSP_VQ_STAGES]; int16_t ilsp0[LPC_ORD], ilsp1[LPC_ORD]; /* Q15 */ int16_t cand, inp_index_cand, tos, intfact; if (firstTime) { temp2 = melpe_shl(LPC_ORD, 10); /* Q10 */ temp1 = X08_Q10; /* Q10 */ for (i = 0; i < LPC_ORD; i++) { /* qplsp[i] = (i+1)*0.8/LPC_ORD; */ qplsp[i] = melpe_divide_s(temp1, temp2); temp1 = melpe_add(temp1, X08_Q10); } firstTime = FALSE; } /* ==== Compute weights ==== */ for (i = 0; i < NF; i++) { lsp[i] = par[i].lsf; lpc_lsp2pred(lsp[i], lpc, LPC_ORD); vq_lspw(wgt[i], lsp[i], lpc, LPC_ORD); } uv_config = 0; for (i = 0; i < NF; i++) { uv_config = melpe_shl(uv_config, 1); if (par[i].uv_flag) { uv_config |= 0x0001; /* ==== Adjust weights ==== */ if (i == 0) /* Testing for par[0].uv_flag == 1 */ v_scale(wgt[0], X02_Q15, LPC_ORD); else if (i == 1) v_scale(wgt[1], X02_Q15, LPC_ORD); } } /* ==== Quantize the lsp according to the UV decisions ==== */ switch (uv_config) { case 7: /* 111, all frames are NOT voiced ---- */ lspVQ(lsp[0], wgt[0], lsp[0], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[0], LPC_ORD, FALSE); lspVQ(lsp[1], wgt[1], lsp[1], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[1], LPC_ORD, FALSE); lspVQ(lsp[2], wgt[2], lsp[2], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[2], LPC_ORD, FALSE); break; case 6: /* 110 */ lspVQ(lsp[0], wgt[0], lsp[0], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[0], LPC_ORD, FALSE); lspVQ(lsp[1], wgt[1], lsp[1], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[1], LPC_ORD, FALSE); lspVQ(lsp[2], wgt[2], lsp[2], lsp_v_256x64x32x32, 4, melp_cb_size, /* !!! (12/15/99) */ quant_par.lsf_index[2], LPC_ORD, FALSE); break; case 5: /* 101 */ lspVQ(lsp[0], wgt[0], lsp[0], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[0], LPC_ORD, FALSE); lspVQ(lsp[1], wgt[1], lsp[1], lsp_v_256x64x32x32, 4, melp_cb_size, /* !!! (12/15/99) */ quant_par.lsf_index[1], LPC_ORD, FALSE); lspVQ(lsp[2], wgt[2], lsp[2], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[2], LPC_ORD, FALSE); break; case 3: /* 011 */ lspVQ(lsp[0], wgt[0], lsp[0], lsp_v_256x64x32x32, 4, melp_cb_size, /* !!! (12/15/99) */ quant_par.lsf_index[0], LPC_ORD, FALSE); lspVQ(lsp[1], wgt[1], lsp[1], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[1], LPC_ORD, FALSE); lspVQ(lsp[2], wgt[2], lsp[2], lsp_uv_9, 1, melp_uv_cb_size, quant_par.lsf_index[2], LPC_ORD, FALSE); break; default: if (uv_config == 1) { /* 001 case, if (!uv1 && !uv2 && uv3). */ /* ---- Interpolation [4 inp + (8+6+6+6) res + 9 uv] ---- */ tos = 1; lspVQ(lsp[2], wgt[2], lsp_cand[0], lsp_uv_9, tos, melp_uv_cb_size, lsp_index_cand, LPC_ORD, TRUE); } else { tos = 4; lspVQ(lsp[2], wgt[2], lsp_cand[0], lsp_v_256x64x32x32, tos, /* !!! (12/15/99) */ melp_cb_size, lsp_index_cand, LPC_ORD, TRUE); } minErr = LW_MAX; cand = 0; inp_index_cand = 0; for (k = 0; k < LSP_INP_CAND; k++) { for (i = 0; i < 16; i++) { err = 0; /* Originally we have two for loops here. One computes */ /* ilsp0[] and ilsp1[] and the other one computes "err". If */ /* "err" already exceeds minErr, we can stop the loop and */ /* there is no need to compute the remaining ilsp0[] and */ /* ilsp1[] entries. Hence the two for loops are joined. */ for (j = 0; j < LPC_ORD; j++) { /* ilsp0[j] = (inpCoef[i][j] * qplsp[j] + (1.0 - inpCoef[i][j]) * lsp_cand[k][j]); */ intfact = inpCoef[i][j]; /* Q14 */ acc = melpe_L_mult(intfact, qplsp[j]); /* Q30 */ intfact = melpe_sub(ONE_Q14, intfact); /* Q14 */ acc = melpe_L_mac(acc, intfact, lsp_cand[k][j]); /* Q30 */ ilsp0[j] = melpe_extract_h(melpe_L_shl(acc, 1)); acc = melpe_L_sub(acc, melpe_L_shl(melpe_L_deposit_l(lsp[0][j]), 15)); /* ilsp1[j] = inpCoef[i][j + LPC_ORD] * qplsp[j] + (1.0 - inpCoef[i][j + LPC_ORD]) * lsp_cand[k][j]; */ intfact = inpCoef[i][j + LPC_ORD]; /* Q14 */ bcc = melpe_L_mult(intfact, qplsp[j]); intfact = melpe_sub(ONE_Q14, intfact); bcc = melpe_L_mac(bcc, intfact, lsp_cand[k][j]); /* Q30 */ ilsp1[j] = melpe_extract_h(melpe_L_shl(bcc, 1)); bcc = melpe_L_sub(bcc, melpe_L_shl(melpe_L_deposit_l(lsp[1][j]), 15)); /* err += wgt0[j]*(lsp0[j] - ilsp0[j])* (lsp0[j] - ilsp0[j]); */ temp1 = melpe_norm_l(acc); temp2 = melpe_extract_h(melpe_L_shl(acc, temp1)); if (temp2 == MONE_Q15) temp2 = -32767; temp2 = melpe_mult(temp2, temp2); acc = melpe_L_mult(temp2, wgt[0][j]); temp1 = melpe_shl(melpe_sub(1, temp1), 1); acc = melpe_L_shl(acc, melpe_sub(temp1, 3)); /* Q24 */ err = melpe_L_add(err, acc); /* err += wgt1[j]*(lsp1[j] - ilsp1[j])* (lsp1[j] - ilsp1[j]); */ temp1 = melpe_norm_l(bcc); temp2 = melpe_extract_h(melpe_L_shl(bcc, temp1)); if (temp2 == MONE_Q15) temp2 = -32767; temp2 = melpe_mult(temp2, temp2); bcc = melpe_L_mult(temp2, wgt[1][j]); temp1 = melpe_shl(melpe_sub(1, temp1), 1); bcc = melpe_L_shl(bcc, melpe_sub(temp1, 3)); /* Q24 */ err = melpe_L_add(err, bcc); /* computer the err for the last frame */ acc = melpe_L_shl(melpe_L_deposit_l(lsp[2][j]), 15); acc = melpe_L_sub(acc, melpe_L_shl(melpe_L_deposit_l (lsp_cand[k][j]), 15)); temp1 = melpe_norm_l(acc); temp2 = melpe_extract_h(melpe_L_shl(acc, temp1)); if (temp2 == MONE_Q15) temp2 = -32767; temp2 = melpe_mult(temp2, temp2); acc = melpe_L_mult(temp2, wgt[2][j]); temp1 = melpe_shl(melpe_sub(1, temp1), 1); acc = melpe_L_shl(acc, melpe_sub(temp1, 3)); /* Q24 */ err = melpe_L_add(err, acc); } if (err < minErr) { minErr = err; cand = k; inp_index_cand = i; v_equ(bestlsp0, ilsp0, LPC_ORD); v_equ(bestlsp1, ilsp1, LPC_ORD); } } } v_equ(lsp[2], lsp_cand[cand], LPC_ORD); v_equ(quant_par.lsf_index[0], &(lsp_index_cand[cand * tos]), tos); quant_par.lsf_index[1][0] = inp_index_cand; for (i = 0; i < LPC_ORD; i++) { temp1 = melpe_sub(lsp[0][i], bestlsp0[i]); /* Q15 */ temp2 = melpe_sub(lsp[1][i], bestlsp1[i]); /* Q15 */ res[i] = melpe_shl(temp1, 2); /* Q17 */ res[i + LPC_ORD] = melpe_shl(temp2, 2); /* Q17 */ } v_equ(mwgt, wgt[0], LPC_ORD); v_equ(mwgt + LPC_ORD, wgt[1], LPC_ORD); /* Note that in the following IF block, the lspVQ() is quantizing on */ /* res[] and res256x64x64x64[], and both of them are Q17 instead of */ /* Q15, unlike the other calling instances in this function. */ if (uv_config == 1) /* if (!uv1 && !uv2 && uv3) */ lspVQ(res, mwgt, res, res256x64x64x64, 4, res_cb_size, quant_par.lsf_index[2], 2 * LPC_ORD, FALSE); else lspVQ(res, mwgt, res, res256x64x64x64, 2, res_cb_size, quant_par.lsf_index[2], 2 * LPC_ORD, FALSE); /* ---- reconstruct lsp for later stability check ---- */ for (i = 0; i < LPC_ORD; i++) { temp1 = melpe_shr(res[i], 2); lsp[0][i] = melpe_add(temp1, bestlsp0[i]); temp2 = melpe_shr(res[i + LPC_ORD], 2); lsp[1][i] = melpe_add(temp2, bestlsp1[i]); } break; } /* ---- Stability checking ---- */ /* The sortings on lsp[0] and lsp[1] are not necessary because they are */ /* variables local to this function and they are discarded upon exit. */ /* We only check whether they fit the stability test and issue a warning. */ (void)lspStable(lsp[0], LPC_ORD); (void)lspStable(lsp[1], LPC_ORD); if (!lspStable(lsp[2], LPC_ORD)) lspSort(lsp[2], LPC_ORD); v_equ(qplsp, lsp[2], LPC_ORD); }
void melp_ana(float sp_in[],struct melp_param *par) { int i; int begin; float sub_pitch; float temp,pcorr,bpthresh; float r[LPC_ORD+1],refc[LPC_ORD+1],lpc[LPC_ORD+1]; float weights[LPC_ORD]; /* Remove DC from input speech */ dc_rmv(sp_in,&speech[IN_BEG],dcdel,FRAME); /* Copy input speech to pitch window and lowpass filter */ v_equ(&sigbuf[LPF_ORD],&speech[PITCH_BEG],PITCH_FR); v_equ(sigbuf,lpfsp_del,LPF_ORD); polflt(&sigbuf[LPF_ORD],lpf_den,&sigbuf[LPF_ORD],LPF_ORD,PITCH_FR); v_equ(lpfsp_del,&sigbuf[FRAME],LPF_ORD); zerflt(&sigbuf[LPF_ORD],lpf_num,&sigbuf[LPF_ORD],LPF_ORD,PITCH_FR); /* Perform global pitch search at frame end on lowpass speech signal */ /* Note: avoid short pitches due to formant tracking */ fpitch[END] = find_pitch(&sigbuf[LPF_ORD+(PITCH_FR/2)],&temp, (2*PITCHMIN),PITCHMAX,PITCHMAX); /* Perform bandpass voicing analysis for end of frame */ bpvc_ana(&speech[FRAME_END], fpitch, &par->bpvc[0], &sub_pitch); /* Force jitter if lowest band voicing strength is weak */ if (par->bpvc[0] < VJIT) par->jitter = MAX_JITTER; else par->jitter = 0.0; /* Calculate LPC for end of frame */ window(&speech[(FRAME_END-(LPC_FRAME/2))],win_cof,sigbuf,LPC_FRAME); autocorr(sigbuf,r,LPC_ORD,LPC_FRAME); lpc[0] = 1.0; lpc_schur(r,lpc,refc,LPC_ORD); lpc_bw_expand(lpc,lpc,BWFACT,LPC_ORD); /* Calculate LPC residual */ zerflt(&speech[PITCH_BEG],lpc,&sigbuf[LPF_ORD],LPC_ORD,PITCH_FR); /* Check peakiness of residual signal */ begin = (LPF_ORD+(PITCHMAX/2)); temp = peakiness(&sigbuf[begin],PITCHMAX); /* Peakiness: force lowest band to be voiced */ if (temp > PEAK_THRESH) { par->bpvc[0] = 1.0; } /* Extreme peakiness: force second and third bands to be voiced */ if (temp > PEAK_THR2) { par->bpvc[1] = 1.0; par->bpvc[2] = 1.0; } /* Calculate overall frame pitch using lowpass filtered residual */ par->pitch = pitch_ana(&speech[FRAME_END], &sigbuf[LPF_ORD+PITCHMAX], sub_pitch,pitch_avg,&pcorr); bpthresh = BPTHRESH; /* Calculate gain of input speech for each gain subframe */ for (i = 0; i < NUM_GAINFR; i++) { if (par->bpvc[0] > bpthresh) { /* voiced mode: pitch synchronous window length */ temp = sub_pitch; par->gain[i] = gain_ana(&speech[FRAME_BEG+(i+1)*GAINFR], temp,MIN_GAINFR,2*PITCHMAX); } else { temp = 1.33*GAINFR - 0.5; par->gain[i] = gain_ana(&speech[FRAME_BEG+(i+1)*GAINFR], temp,0,2*PITCHMAX); } } /* Update average pitch value */ if (par->gain[NUM_GAINFR-1] > SILENCE_DB) temp = pcorr; else temp = 0.0; pitch_avg = p_avg_update(par->pitch, temp, VMIN); /* Calculate Line Spectral Frequencies */ lpc_pred2lsp(lpc,par->lsf,LPC_ORD); /* Force minimum LSF bandwidth (separation) */ lpc_clamp(par->lsf,BWMIN,LPC_ORD); /* Quantize MELP parameters to 2400 bps and generate bitstream */ /* Quantize LSF's with MSVQ */ vq_lspw(weights, &par->lsf[1], lpc, LPC_ORD); msvq_enc(&par->lsf[1], weights, &par->lsf[1], vq_par); par->msvq_index = vq_par.indices; /* Force minimum LSF bandwidth (separation) */ lpc_clamp(par->lsf,BWMIN,LPC_ORD); /* Quantize logarithmic pitch period */ /* Reserve all zero code for completely unvoiced */ par->pitch = log10(par->pitch); quant_u(&par->pitch,&par->pitch_index,PIT_QLO,PIT_QUP,PIT_QLEV); par->pitch = pow(10.0,par->pitch); /* Quantize gain terms with uniform log quantizer */ q_gain(par->gain, par->gain_index,GN_QLO,GN_QUP,GN_QLEV); /* Quantize jitter and bandpass voicing */ quant_u(&par->jitter,&par->jit_index,0.0,MAX_JITTER,2); par->uv_flag = q_bpvc(&par->bpvc[0],&par->bpvc_index,bpthresh, NUM_BANDS); /* Calculate Fourier coefficients of residual signal from quantized LPC */ fill(par->fs_mag,1.0,NUM_HARM); if (par->bpvc[0] > bpthresh) { lpc_lsp2pred(par->lsf,lpc,LPC_ORD); zerflt(&speech[(FRAME_END-(LPC_FRAME/2))],lpc,sigbuf, LPC_ORD,LPC_FRAME); window(sigbuf,win_cof,sigbuf,LPC_FRAME); find_harm(sigbuf, par->fs_mag, par->pitch, NUM_HARM, LPC_FRAME); } /* quantize Fourier coefficients */ /* pre-weight vector, then use Euclidean distance */ window(&par->fs_mag[0],w_fs,&par->fs_mag[0],NUM_HARM); fsvq_enc(&par->fs_mag[0], &par->fs_mag[0], fs_vq_par); /* Set MELP indeces to point to same array */ par->fsvq_index = fs_vq_par.indices; /* Update MSVQ information */ par->msvq_stages = vq_par.num_stages; par->msvq_bits = vq_par.num_bits; /* Write channel bitstream */ melp_chn_write(par); /* Update delay buffers for next frame */ v_equ(&speech[0],&speech[FRAME],IN_BEG); fpitch[BEGIN] = fpitch[END]; }