/* Transform a masking curve (power spectrum) into a pole-zero filter */ void curve_to_lpc(VorbisPsy *psy, float *curve, float *awk1, float *awk2, int ord) { int i; float ac[psy->n]; float tmp; int len = psy->n >> 1; for (i=0;i<2*len;i++) ac[i] = 0; for (i=1;i<len;i++) ac[2*i-1] = curve[i]; ac[0] = curve[0]; ac[2*len-1] = curve[len-1]; spx_drft_backward(&psy->lookup, ac); _spx_lpc(awk1, ac, ord); tmp = 1.; for (i=0;i<ord;i++) { tmp *= .99; awk1[i] *= tmp; } #if 0 for (i=0;i<ord;i++) awk2[i] = 0; #else /* Use the second (awk2) filter to correct the first one */ for (i=0;i<2*len;i++) ac[i] = 0; for (i=0;i<ord;i++) ac[i+1] = awk1[i]; ac[0] = 1; spx_drft_forward(&psy->lookup, ac); /* Compute (power) response of awk1 (all zero) */ ac[0] *= ac[0]; for (i=1;i<len;i++) ac[i] = ac[2*i-1]*ac[2*i-1] + ac[2*i]*ac[2*i]; ac[len] = ac[2*len-1]*ac[2*len-1]; /* Compute correction required */ for (i=0;i<len;i++) curve[i] = 1. / (1e-6f+curve[i]*ac[i]); for (i=0;i<2*len;i++) ac[i] = 0; for (i=1;i<len;i++) ac[2*i-1] = curve[i]; ac[0] = curve[0]; ac[2*len-1] = curve[len-1]; spx_drft_backward(&psy->lookup, ac); _spx_lpc(awk2, ac, ord); tmp = 1; for (i=0;i<ord;i++) { tmp *= .99; awk2[i] *= tmp; } #endif }
int sb_encode(void *state, void *vin, SpeexBits *bits) { SBEncState *st; int i, roots, sub; char *stack; VARDECL(spx_mem_t *mem); VARDECL(spx_sig_t *innov); VARDECL(spx_word16_t *target); VARDECL(spx_word16_t *syn_resp); VARDECL(spx_word32_t *low_pi_gain); spx_word16_t *low; spx_word16_t *high; VARDECL(spx_word16_t *low_exc_rms); VARDECL(spx_word16_t *low_innov_rms); const SpeexSBMode *mode; spx_int32_t dtx; spx_word16_t *in = (spx_word16_t*)vin; spx_word16_t e_low=0, e_high=0; VARDECL(spx_coef_t *lpc); VARDECL(spx_coef_t *interp_lpc); VARDECL(spx_coef_t *bw_lpc1); VARDECL(spx_coef_t *bw_lpc2); VARDECL(spx_lsp_t *lsp); VARDECL(spx_lsp_t *qlsp); VARDECL(spx_lsp_t *interp_lsp); VARDECL(spx_lsp_t *interp_qlsp); st = (SBEncState*)state; stack=st->stack; mode = (const SpeexSBMode*)(st->mode->mode); low = in; high = in+st->frame_size; /* High-band buffering / sync with low band */ /* Compute the two sub-bands by filtering with QMF h0*/ qmf_decomp(in, h0, low, high, st->full_frame_size, QMF_ORDER, st->h0_mem, stack); #ifndef DISABLE_VBR if (st->vbr_enabled || st->vad_enabled) { /* Need to compute things here before the signal is trashed by the encoder */ /*FIXME: Are the two signals (low, high) in sync? */ e_low = compute_rms16(low, st->frame_size); e_high = compute_rms16(high, st->frame_size); } #endif /* #ifndef DISABLE_VBR */ ALLOC(low_innov_rms, st->nbSubframes, spx_word16_t); speex_encoder_ctl(st->st_low, SPEEX_SET_INNOVATION_SAVE, low_innov_rms); /* Encode the narrowband part*/ speex_encode_native(st->st_low, low, bits); high = high - (st->windowSize-st->frame_size); SPEEX_COPY(high, st->high, st->windowSize-st->frame_size); SPEEX_COPY(st->high, &high[st->frame_size], st->windowSize-st->frame_size); ALLOC(low_pi_gain, st->nbSubframes, spx_word32_t); ALLOC(low_exc_rms, st->nbSubframes, spx_word16_t); speex_encoder_ctl(st->st_low, SPEEX_GET_PI_GAIN, low_pi_gain); speex_encoder_ctl(st->st_low, SPEEX_GET_EXC, low_exc_rms); speex_encoder_ctl(st->st_low, SPEEX_GET_LOW_MODE, &dtx); if (dtx==0) dtx=1; else dtx=0; ALLOC(lpc, st->lpcSize, spx_coef_t); ALLOC(interp_lpc, st->lpcSize, spx_coef_t); ALLOC(bw_lpc1, st->lpcSize, spx_coef_t); ALLOC(bw_lpc2, st->lpcSize, spx_coef_t); ALLOC(lsp, st->lpcSize, spx_lsp_t); ALLOC(qlsp, st->lpcSize, spx_lsp_t); ALLOC(interp_lsp, st->lpcSize, spx_lsp_t); ALLOC(interp_qlsp, st->lpcSize, spx_lsp_t); { VARDECL(spx_word16_t *autocorr); VARDECL(spx_word16_t *w_sig); ALLOC(autocorr, st->lpcSize+1, spx_word16_t); ALLOC(w_sig, st->windowSize, spx_word16_t); /* Window for analysis */ /* FIXME: This is a kludge */ if (st->subframeSize==80) { for (i=0;i<st->windowSize;i++) w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i>>1]),SIG_SHIFT)); } else { for (i=0;i<st->windowSize;i++) w_sig[i] = EXTRACT16(SHR32(MULT16_16(high[i],st->window[i]),SIG_SHIFT)); } /* Compute auto-correlation */ _spx_autocorr(w_sig, autocorr, st->lpcSize+1, st->windowSize); autocorr[0] = ADD16(autocorr[0],MULT16_16_Q15(autocorr[0],st->lpc_floor)); /* Noise floor in auto-correlation domain */ /* Lag windowing: equivalent to filtering in the power-spectrum domain */ for (i=0;i<st->lpcSize+1;i++) autocorr[i] = MULT16_16_Q14(autocorr[i],st->lagWindow[i]); /* Levinson-Durbin */ _spx_lpc(lpc, autocorr, st->lpcSize); }