/* | |
** Copyright 2003-2010, VisualOn, Inc. | |
** | |
** Licensed under the Apache License, Version 2.0 (the "License"); | |
** you may not use this file except in compliance with the License. | |
** You may obtain a copy of the License at | |
** | |
** http://www.apache.org/licenses/LICENSE-2.0 | |
** | |
** Unless required by applicable law or agreed to in writing, software | |
** distributed under the License is distributed on an "AS IS" BASIS, | |
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
** See the License for the specific language governing permissions and | |
** limitations under the License. | |
*/ | |
/*********************************************************************** | |
* File: voAMRWBEnc.c * | |
* * | |
* Description: Performs the main encoder routine * | |
* Fixed-point C simulation of AMR WB ACELP coding * | |
* algorithm with 20 msspeech frames for * | |
* wideband speech signals. * | |
* * | |
************************************************************************/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include "typedef.h" | |
#include "basic_op.h" | |
#include "oper_32b.h" | |
#include "math_op.h" | |
#include "cnst.h" | |
#include "acelp.h" | |
#include "cod_main.h" | |
#include "bits.h" | |
#include "main.h" | |
#include "voAMRWB.h" | |
#include "mem_align.h" | |
#include "cmnMemory.h" | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
/* LPC interpolation coef {0.45, 0.8, 0.96, 1.0}; in Q15 */ | |
static Word16 interpol_frac[NB_SUBFR] = {14746, 26214, 31457, 32767}; | |
/* isp tables for initialization */ | |
static Word16 isp_init[M] = | |
{ | |
32138, 30274, 27246, 23170, 18205, 12540, 6393, 0, | |
-6393, -12540, -18205, -23170, -27246, -30274, -32138, 1475 | |
}; | |
static Word16 isf_init[M] = | |
{ | |
1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, | |
9216, 10240, 11264, 12288, 13312, 14336, 15360, 3840 | |
}; | |
/* High Band encoding */ | |
static const Word16 HP_gain[16] = | |
{ | |
3624, 4673, 5597, 6479, 7425, 8378, 9324, 10264, | |
11210, 12206, 13391, 14844, 16770, 19655, 24289, 32728 | |
}; | |
/* Private function declaration */ | |
static Word16 synthesis( | |
Word16 Aq[], /* A(z) : quantized Az */ | |
Word16 exc[], /* (i) : excitation at 12kHz */ | |
Word16 Q_new, /* (i) : scaling performed on exc */ | |
Word16 synth16k[], /* (o) : 16kHz synthesis signal */ | |
Coder_State * st /* (i/o) : State structure */ | |
); | |
/* Codec some parameters initialization */ | |
void Reset_encoder(void *st, Word16 reset_all) | |
{ | |
Word16 i; | |
Coder_State *cod_state; | |
cod_state = (Coder_State *) st; | |
Set_zero(cod_state->old_exc, PIT_MAX + L_INTERPOL); | |
Set_zero(cod_state->mem_syn, M); | |
Set_zero(cod_state->past_isfq, M); | |
cod_state->mem_w0 = 0; | |
cod_state->tilt_code = 0; | |
cod_state->first_frame = 1; | |
Init_gp_clip(cod_state->gp_clip); | |
cod_state->L_gc_thres = 0; | |
if (reset_all != 0) | |
{ | |
/* Static vectors to zero */ | |
Set_zero(cod_state->old_speech, L_TOTAL - L_FRAME); | |
Set_zero(cod_state->old_wsp, (PIT_MAX / OPL_DECIM)); | |
Set_zero(cod_state->mem_decim2, 3); | |
/* routines initialization */ | |
Init_Decim_12k8(cod_state->mem_decim); | |
Init_HP50_12k8(cod_state->mem_sig_in); | |
Init_Levinson(cod_state->mem_levinson); | |
Init_Q_gain2(cod_state->qua_gain); | |
Init_Hp_wsp(cod_state->hp_wsp_mem); | |
/* isp initialization */ | |
Copy(isp_init, cod_state->ispold, M); | |
Copy(isp_init, cod_state->ispold_q, M); | |
/* variable initialization */ | |
cod_state->mem_preemph = 0; | |
cod_state->mem_wsp = 0; | |
cod_state->Q_old = 15; | |
cod_state->Q_max[0] = 15; | |
cod_state->Q_max[1] = 15; | |
cod_state->old_wsp_max = 0; | |
cod_state->old_wsp_shift = 0; | |
/* pitch ol initialization */ | |
cod_state->old_T0_med = 40; | |
cod_state->ol_gain = 0; | |
cod_state->ada_w = 0; | |
cod_state->ol_wght_flg = 0; | |
for (i = 0; i < 5; i++) | |
{ | |
cod_state->old_ol_lag[i] = 40; | |
} | |
Set_zero(cod_state->old_hp_wsp, (L_FRAME / 2) / OPL_DECIM + (PIT_MAX / OPL_DECIM)); | |
Set_zero(cod_state->mem_syn_hf, M); | |
Set_zero(cod_state->mem_syn_hi, M); | |
Set_zero(cod_state->mem_syn_lo, M); | |
Init_HP50_12k8(cod_state->mem_sig_out); | |
Init_Filt_6k_7k(cod_state->mem_hf); | |
Init_HP400_12k8(cod_state->mem_hp400); | |
Copy(isf_init, cod_state->isfold, M); | |
cod_state->mem_deemph = 0; | |
cod_state->seed2 = 21845; | |
Init_Filt_6k_7k(cod_state->mem_hf2); | |
cod_state->gain_alpha = 32767; | |
cod_state->vad_hist = 0; | |
wb_vad_reset(cod_state->vadSt); | |
dtx_enc_reset(cod_state->dtx_encSt, isf_init); | |
} | |
return; | |
} | |
/*-----------------------------------------------------------------* | |
* Funtion coder * | |
* ~~~~~ * | |
* ->Main coder routine. * | |
* * | |
*-----------------------------------------------------------------*/ | |
void coder( | |
Word16 * mode, /* input : used mode */ | |
Word16 speech16k[], /* input : 320 new speech samples (at 16 kHz) */ | |
Word16 prms[], /* output: output parameters */ | |
Word16 * ser_size, /* output: bit rate of the used mode */ | |
void *spe_state, /* i/o : State structure */ | |
Word16 allow_dtx /* input : DTX ON/OFF */ | |
) | |
{ | |
/* Coder states */ | |
Coder_State *st; | |
/* Speech vector */ | |
Word16 old_speech[L_TOTAL]; | |
Word16 *new_speech, *speech, *p_window; | |
/* Weighted speech vector */ | |
Word16 old_wsp[L_FRAME + (PIT_MAX / OPL_DECIM)]; | |
Word16 *wsp; | |
/* Excitation vector */ | |
Word16 old_exc[(L_FRAME + 1) + PIT_MAX + L_INTERPOL]; | |
Word16 *exc; | |
/* LPC coefficients */ | |
Word16 r_h[M + 1], r_l[M + 1]; /* Autocorrelations of windowed speech */ | |
Word16 rc[M]; /* Reflection coefficients. */ | |
Word16 Ap[M + 1]; /* A(z) with spectral expansion */ | |
Word16 ispnew[M]; /* immittance spectral pairs at 4nd sfr */ | |
Word16 ispnew_q[M]; /* quantized ISPs at 4nd subframe */ | |
Word16 isf[M]; /* ISF (frequency domain) at 4nd sfr */ | |
Word16 *p_A, *p_Aq; /* ptr to A(z) for the 4 subframes */ | |
Word16 A[NB_SUBFR * (M + 1)]; /* A(z) unquantized for the 4 subframes */ | |
Word16 Aq[NB_SUBFR * (M + 1)]; /* A(z) quantized for the 4 subframes */ | |
/* Other vectors */ | |
Word16 xn[L_SUBFR]; /* Target vector for pitch search */ | |
Word16 xn2[L_SUBFR]; /* Target vector for codebook search */ | |
Word16 dn[L_SUBFR]; /* Correlation between xn2 and h1 */ | |
Word16 cn[L_SUBFR]; /* Target vector in residual domain */ | |
Word16 h1[L_SUBFR]; /* Impulse response vector */ | |
Word16 h2[L_SUBFR]; /* Impulse response vector */ | |
Word16 code[L_SUBFR]; /* Fixed codebook excitation */ | |
Word16 y1[L_SUBFR]; /* Filtered adaptive excitation */ | |
Word16 y2[L_SUBFR]; /* Filtered adaptive excitation */ | |
Word16 error[M + L_SUBFR]; /* error of quantization */ | |
Word16 synth[L_SUBFR]; /* 12.8kHz synthesis vector */ | |
Word16 exc2[L_FRAME]; /* excitation vector */ | |
Word16 buf[L_FRAME]; /* VAD buffer */ | |
/* Scalars */ | |
Word32 i, j, i_subfr, select, pit_flag, clip_gain, vad_flag; | |
Word16 codec_mode; | |
Word16 T_op, T_op2, T0, T0_min, T0_max, T0_frac, index; | |
Word16 gain_pit, gain_code, g_coeff[4], g_coeff2[4]; | |
Word16 tmp, gain1, gain2, exp, Q_new, mu, shift, max; | |
Word16 voice_fac; | |
Word16 indice[8]; | |
Word32 L_tmp, L_gain_code, L_max, L_tmp1; | |
Word16 code2[L_SUBFR]; /* Fixed codebook excitation */ | |
Word16 stab_fac, fac, gain_code_lo; | |
Word16 corr_gain; | |
Word16 *vo_p0, *vo_p1, *vo_p2, *vo_p3; | |
st = (Coder_State *) spe_state; | |
*ser_size = nb_of_bits[*mode]; | |
codec_mode = *mode; | |
/*--------------------------------------------------------------------------* | |
* Initialize pointers to speech vector. * | |
* * | |
* * | |
* |-------|-------|-------|-------|-------|-------| * | |
* past sp sf1 sf2 sf3 sf4 L_NEXT * | |
* <------- Total speech buffer (L_TOTAL) ------> * | |
* old_speech * | |
* <------- LPC analysis window (L_WINDOW) ------> * | |
* | <-- present frame (L_FRAME) ----> * | |
* p_window | <----- new speech (L_FRAME) ----> * | |
* | | * | |
* speech | * | |
* new_speech * | |
*--------------------------------------------------------------------------*/ | |
new_speech = old_speech + L_TOTAL - L_FRAME - L_FILT; /* New speech */ | |
speech = old_speech + L_TOTAL - L_FRAME - L_NEXT; /* Present frame */ | |
p_window = old_speech + L_TOTAL - L_WINDOW; | |
exc = old_exc + PIT_MAX + L_INTERPOL; | |
wsp = old_wsp + (PIT_MAX / OPL_DECIM); | |
/* copy coder memory state into working space */ | |
Copy(st->old_speech, old_speech, L_TOTAL - L_FRAME); | |
Copy(st->old_wsp, old_wsp, PIT_MAX / OPL_DECIM); | |
Copy(st->old_exc, old_exc, PIT_MAX + L_INTERPOL); | |
/*---------------------------------------------------------------* | |
* Down sampling signal from 16kHz to 12.8kHz * | |
* -> The signal is extended by L_FILT samples (padded to zero) * | |
* to avoid additional delay (L_FILT samples) in the coder. * | |
* The last L_FILT samples are approximated after decimation and * | |
* are used (and windowed) only in autocorrelations. * | |
*---------------------------------------------------------------*/ | |
Decim_12k8(speech16k, L_FRAME16k, new_speech, st->mem_decim); | |
/* last L_FILT samples for autocorrelation window */ | |
Copy(st->mem_decim, code, 2 * L_FILT16k); | |
Set_zero(error, L_FILT16k); /* set next sample to zero */ | |
Decim_12k8(error, L_FILT16k, new_speech + L_FRAME, code); | |
/*---------------------------------------------------------------* | |
* Perform 50Hz HP filtering of input signal. * | |
*---------------------------------------------------------------*/ | |
HP50_12k8(new_speech, L_FRAME, st->mem_sig_in); | |
/* last L_FILT samples for autocorrelation window */ | |
Copy(st->mem_sig_in, code, 6); | |
HP50_12k8(new_speech + L_FRAME, L_FILT, code); | |
/*---------------------------------------------------------------* | |
* Perform fixed preemphasis through 1 - g z^-1 * | |
* Scale signal to get maximum of precision in filtering * | |
*---------------------------------------------------------------*/ | |
mu = PREEMPH_FAC >> 1; /* Q15 --> Q14 */ | |
/* get max of new preemphased samples (L_FRAME+L_FILT) */ | |
L_tmp = new_speech[0] << 15; | |
L_tmp -= (st->mem_preemph * mu)<<1; | |
L_max = L_abs(L_tmp); | |
for (i = 1; i < L_FRAME + L_FILT; i++) | |
{ | |
L_tmp = new_speech[i] << 15; | |
L_tmp -= (new_speech[i - 1] * mu)<<1; | |
L_tmp = L_abs(L_tmp); | |
if(L_tmp > L_max) | |
{ | |
L_max = L_tmp; | |
} | |
} | |
/* get scaling factor for new and previous samples */ | |
/* limit scaling to Q_MAX to keep dynamic for ringing in low signal */ | |
/* limit scaling to Q_MAX also to avoid a[0]<1 in syn_filt_32 */ | |
tmp = extract_h(L_max); | |
if (tmp == 0) | |
{ | |
shift = Q_MAX; | |
} else | |
{ | |
shift = norm_s(tmp) - 1; | |
if (shift < 0) | |
{ | |
shift = 0; | |
} | |
if (shift > Q_MAX) | |
{ | |
shift = Q_MAX; | |
} | |
} | |
Q_new = shift; | |
if (Q_new > st->Q_max[0]) | |
{ | |
Q_new = st->Q_max[0]; | |
} | |
if (Q_new > st->Q_max[1]) | |
{ | |
Q_new = st->Q_max[1]; | |
} | |
exp = (Q_new - st->Q_old); | |
st->Q_old = Q_new; | |
st->Q_max[1] = st->Q_max[0]; | |
st->Q_max[0] = shift; | |
/* preemphasis with scaling (L_FRAME+L_FILT) */ | |
tmp = new_speech[L_FRAME - 1]; | |
for (i = L_FRAME + L_FILT - 1; i > 0; i--) | |
{ | |
L_tmp = new_speech[i] << 15; | |
L_tmp -= (new_speech[i - 1] * mu)<<1; | |
L_tmp = (L_tmp << Q_new); | |
new_speech[i] = vo_round(L_tmp); | |
} | |
L_tmp = new_speech[0] << 15; | |
L_tmp -= (st->mem_preemph * mu)<<1; | |
L_tmp = (L_tmp << Q_new); | |
new_speech[0] = vo_round(L_tmp); | |
st->mem_preemph = tmp; | |
/* scale previous samples and memory */ | |
Scale_sig(old_speech, L_TOTAL - L_FRAME - L_FILT, exp); | |
Scale_sig(old_exc, PIT_MAX + L_INTERPOL, exp); | |
Scale_sig(st->mem_syn, M, exp); | |
Scale_sig(st->mem_decim2, 3, exp); | |
Scale_sig(&(st->mem_wsp), 1, exp); | |
Scale_sig(&(st->mem_w0), 1, exp); | |
/*------------------------------------------------------------------------* | |
* Call VAD * | |
* Preemphesis scale down signal in low frequency and keep dynamic in HF.* | |
* Vad work slightly in futur (new_speech = speech + L_NEXT - L_FILT). * | |
*------------------------------------------------------------------------*/ | |
Copy(new_speech, buf, L_FRAME); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Scale_sig_opt(buf, L_FRAME, 1 - Q_new); | |
#else | |
Scale_sig(buf, L_FRAME, 1 - Q_new); | |
#endif | |
vad_flag = wb_vad(st->vadSt, buf); /* Voice Activity Detection */ | |
if (vad_flag == 0) | |
{ | |
st->vad_hist = (st->vad_hist + 1); | |
} else | |
{ | |
st->vad_hist = 0; | |
} | |
/* DTX processing */ | |
if (allow_dtx != 0) | |
{ | |
/* Note that mode may change here */ | |
tx_dtx_handler(st->dtx_encSt, vad_flag, mode); | |
*ser_size = nb_of_bits[*mode]; | |
} | |
if(*mode != MRDTX) | |
{ | |
Parm_serial(vad_flag, 1, &prms); | |
} | |
/*------------------------------------------------------------------------* | |
* Perform LPC analysis * | |
* ~~~~~~~~~~~~~~~~~~~~ * | |
* - autocorrelation + lag windowing * | |
* - Levinson-durbin algorithm to find a[] * | |
* - convert a[] to isp[] * | |
* - convert isp[] to isf[] for quantization * | |
* - quantize and code the isf[] * | |
* - convert isf[] to isp[] for interpolation * | |
* - find the interpolated ISPs and convert to a[] for the 4 subframes * | |
*------------------------------------------------------------------------*/ | |
/* LP analysis centered at 4nd subframe */ | |
Autocorr(p_window, M, r_h, r_l); /* Autocorrelations */ | |
Lag_window(r_h, r_l); /* Lag windowing */ | |
Levinson(r_h, r_l, A, rc, st->mem_levinson); /* Levinson Durbin */ | |
Az_isp(A, ispnew, st->ispold); /* From A(z) to ISP */ | |
/* Find the interpolated ISPs and convert to a[] for all subframes */ | |
Int_isp(st->ispold, ispnew, interpol_frac, A); | |
/* update ispold[] for the next frame */ | |
Copy(ispnew, st->ispold, M); | |
/* Convert ISPs to frequency domain 0..6400 */ | |
Isp_isf(ispnew, isf, M); | |
/* check resonance for pitch clipping algorithm */ | |
Gp_clip_test_isf(isf, st->gp_clip); | |
/*----------------------------------------------------------------------* | |
* Perform PITCH_OL analysis * | |
* ~~~~~~~~~~~~~~~~~~~~~~~~~ * | |
* - Find the residual res[] for the whole speech frame * | |
* - Find the weighted input speech wsp[] for the whole speech frame * | |
* - scale wsp[] to avoid overflow in pitch estimation * | |
* - Find open loop pitch lag for whole speech frame * | |
*----------------------------------------------------------------------*/ | |
p_A = A; | |
for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) | |
{ | |
/* Weighting of LPC coefficients */ | |
Weight_a(p_A, Ap, GAMMA1, M); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Residu_opt(Ap, &speech[i_subfr], &wsp[i_subfr], L_SUBFR); | |
#else | |
Residu(Ap, &speech[i_subfr], &wsp[i_subfr], L_SUBFR); | |
#endif | |
p_A += (M + 1); | |
} | |
Deemph2(wsp, TILT_FAC, L_FRAME, &(st->mem_wsp)); | |
/* find maximum value on wsp[] for 12 bits scaling */ | |
max = 0; | |
for (i = 0; i < L_FRAME; i++) | |
{ | |
tmp = abs_s(wsp[i]); | |
if(tmp > max) | |
{ | |
max = tmp; | |
} | |
} | |
tmp = st->old_wsp_max; | |
if(max > tmp) | |
{ | |
tmp = max; /* tmp = max(wsp_max, old_wsp_max) */ | |
} | |
st->old_wsp_max = max; | |
shift = norm_s(tmp) - 3; | |
if (shift > 0) | |
{ | |
shift = 0; /* shift = 0..-3 */ | |
} | |
/* decimation of wsp[] to search pitch in LF and to reduce complexity */ | |
LP_Decim2(wsp, L_FRAME, st->mem_decim2); | |
/* scale wsp[] in 12 bits to avoid overflow */ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Scale_sig_opt(wsp, L_FRAME / OPL_DECIM, shift); | |
#else | |
Scale_sig(wsp, L_FRAME / OPL_DECIM, shift); | |
#endif | |
/* scale old_wsp (warning: exp must be Q_new-Q_old) */ | |
exp = exp + (shift - st->old_wsp_shift); | |
st->old_wsp_shift = shift; | |
Scale_sig(old_wsp, PIT_MAX / OPL_DECIM, exp); | |
Scale_sig(st->old_hp_wsp, PIT_MAX / OPL_DECIM, exp); | |
scale_mem_Hp_wsp(st->hp_wsp_mem, exp); | |
/* Find open loop pitch lag for whole speech frame */ | |
if(*ser_size == NBBITS_7k) | |
{ | |
/* Find open loop pitch lag for whole speech frame */ | |
T_op = Pitch_med_ol(wsp, st, L_FRAME / OPL_DECIM); | |
} else | |
{ | |
/* Find open loop pitch lag for first 1/2 frame */ | |
T_op = Pitch_med_ol(wsp, st, (L_FRAME/2) / OPL_DECIM); | |
} | |
if(st->ol_gain > 19661) /* 0.6 in Q15 */ | |
{ | |
st->old_T0_med = Med_olag(T_op, st->old_ol_lag); | |
st->ada_w = 32767; | |
} else | |
{ | |
st->ada_w = vo_mult(st->ada_w, 29491); | |
} | |
if(st->ada_w < 26214) | |
st->ol_wght_flg = 0; | |
else | |
st->ol_wght_flg = 1; | |
wb_vad_tone_detection(st->vadSt, st->ol_gain); | |
T_op *= OPL_DECIM; | |
if(*ser_size != NBBITS_7k) | |
{ | |
/* Find open loop pitch lag for second 1/2 frame */ | |
T_op2 = Pitch_med_ol(wsp + ((L_FRAME / 2) / OPL_DECIM), st, (L_FRAME/2) / OPL_DECIM); | |
if(st->ol_gain > 19661) /* 0.6 in Q15 */ | |
{ | |
st->old_T0_med = Med_olag(T_op2, st->old_ol_lag); | |
st->ada_w = 32767; | |
} else | |
{ | |
st->ada_w = mult(st->ada_w, 29491); | |
} | |
if(st->ada_w < 26214) | |
st->ol_wght_flg = 0; | |
else | |
st->ol_wght_flg = 1; | |
wb_vad_tone_detection(st->vadSt, st->ol_gain); | |
T_op2 *= OPL_DECIM; | |
} else | |
{ | |
T_op2 = T_op; | |
} | |
/*----------------------------------------------------------------------* | |
* DTX-CNG * | |
*----------------------------------------------------------------------*/ | |
if(*mode == MRDTX) /* CNG mode */ | |
{ | |
/* Buffer isf's and energy */ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Residu_opt(&A[3 * (M + 1)], speech, exc, L_FRAME); | |
#else | |
Residu(&A[3 * (M + 1)], speech, exc, L_FRAME); | |
#endif | |
for (i = 0; i < L_FRAME; i++) | |
{ | |
exc2[i] = shr(exc[i], Q_new); | |
} | |
L_tmp = 0; | |
for (i = 0; i < L_FRAME; i++) | |
L_tmp += (exc2[i] * exc2[i])<<1; | |
L_tmp >>= 1; | |
dtx_buffer(st->dtx_encSt, isf, L_tmp, codec_mode); | |
/* Quantize and code the ISFs */ | |
dtx_enc(st->dtx_encSt, isf, exc2, &prms); | |
/* Convert ISFs to the cosine domain */ | |
Isf_isp(isf, ispnew_q, M); | |
Isp_Az(ispnew_q, Aq, M, 0); | |
for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) | |
{ | |
corr_gain = synthesis(Aq, &exc2[i_subfr], 0, &speech16k[i_subfr * 5 / 4], st); | |
} | |
Copy(isf, st->isfold, M); | |
/* reset speech coder memories */ | |
Reset_encoder(st, 0); | |
/*--------------------------------------------------* | |
* Update signal for next frame. * | |
* -> save past of speech[] and wsp[]. * | |
*--------------------------------------------------*/ | |
Copy(&old_speech[L_FRAME], st->old_speech, L_TOTAL - L_FRAME); | |
Copy(&old_wsp[L_FRAME / OPL_DECIM], st->old_wsp, PIT_MAX / OPL_DECIM); | |
return; | |
} | |
/*----------------------------------------------------------------------* | |
* ACELP * | |
*----------------------------------------------------------------------*/ | |
/* Quantize and code the ISFs */ | |
if (*ser_size <= NBBITS_7k) | |
{ | |
Qpisf_2s_36b(isf, isf, st->past_isfq, indice, 4); | |
Parm_serial(indice[0], 8, &prms); | |
Parm_serial(indice[1], 8, &prms); | |
Parm_serial(indice[2], 7, &prms); | |
Parm_serial(indice[3], 7, &prms); | |
Parm_serial(indice[4], 6, &prms); | |
} else | |
{ | |
Qpisf_2s_46b(isf, isf, st->past_isfq, indice, 4); | |
Parm_serial(indice[0], 8, &prms); | |
Parm_serial(indice[1], 8, &prms); | |
Parm_serial(indice[2], 6, &prms); | |
Parm_serial(indice[3], 7, &prms); | |
Parm_serial(indice[4], 7, &prms); | |
Parm_serial(indice[5], 5, &prms); | |
Parm_serial(indice[6], 5, &prms); | |
} | |
/* Check stability on isf : distance between old isf and current isf */ | |
L_tmp = 0; | |
for (i = 0; i < M - 1; i++) | |
{ | |
tmp = vo_sub(isf[i], st->isfold[i]); | |
L_tmp += (tmp * tmp)<<1; | |
} | |
tmp = extract_h(L_shl2(L_tmp, 8)); | |
tmp = vo_mult(tmp, 26214); /* tmp = L_tmp*0.8/256 */ | |
tmp = vo_sub(20480, tmp); /* 1.25 - tmp (in Q14) */ | |
stab_fac = shl(tmp, 1); | |
if (stab_fac < 0) | |
{ | |
stab_fac = 0; | |
} | |
Copy(isf, st->isfold, M); | |
/* Convert ISFs to the cosine domain */ | |
Isf_isp(isf, ispnew_q, M); | |
if (st->first_frame != 0) | |
{ | |
st->first_frame = 0; | |
Copy(ispnew_q, st->ispold_q, M); | |
} | |
/* Find the interpolated ISPs and convert to a[] for all subframes */ | |
Int_isp(st->ispold_q, ispnew_q, interpol_frac, Aq); | |
/* update ispold[] for the next frame */ | |
Copy(ispnew_q, st->ispold_q, M); | |
p_Aq = Aq; | |
for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) | |
{ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Residu_opt(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR); | |
#else | |
Residu(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR); | |
#endif | |
p_Aq += (M + 1); | |
} | |
/* Buffer isf's and energy for dtx on non-speech frame */ | |
if (vad_flag == 0) | |
{ | |
for (i = 0; i < L_FRAME; i++) | |
{ | |
exc2[i] = exc[i] >> Q_new; | |
} | |
L_tmp = 0; | |
for (i = 0; i < L_FRAME; i++) | |
L_tmp += (exc2[i] * exc2[i])<<1; | |
L_tmp >>= 1; | |
dtx_buffer(st->dtx_encSt, isf, L_tmp, codec_mode); | |
} | |
/* range for closed loop pitch search in 1st subframe */ | |
T0_min = T_op - 8; | |
if (T0_min < PIT_MIN) | |
{ | |
T0_min = PIT_MIN; | |
} | |
T0_max = (T0_min + 15); | |
if(T0_max > PIT_MAX) | |
{ | |
T0_max = PIT_MAX; | |
T0_min = T0_max - 15; | |
} | |
/*------------------------------------------------------------------------* | |
* Loop for every subframe in the analysis frame * | |
*------------------------------------------------------------------------* | |
* To find the pitch and innovation parameters. The subframe size is * | |
* L_SUBFR and the loop is repeated L_FRAME/L_SUBFR times. * | |
* - compute the target signal for pitch search * | |
* - compute impulse response of weighted synthesis filter (h1[]) * | |
* - find the closed-loop pitch parameters * | |
* - encode the pitch dealy * | |
* - find 2 lt prediction (with / without LP filter for lt pred) * | |
* - find 2 pitch gains and choose the best lt prediction. * | |
* - find target vector for codebook search * | |
* - update the impulse response h1[] for codebook search * | |
* - correlation between target vector and impulse response * | |
* - codebook search and encoding * | |
* - VQ of pitch and codebook gains * | |
* - find voicing factor and tilt of code for next subframe. * | |
* - update states of weighting filter * | |
* - find excitation and synthesis speech * | |
*------------------------------------------------------------------------*/ | |
p_A = A; | |
p_Aq = Aq; | |
for (i_subfr = 0; i_subfr < L_FRAME; i_subfr += L_SUBFR) | |
{ | |
pit_flag = i_subfr; | |
if ((i_subfr == 2 * L_SUBFR) && (*ser_size > NBBITS_7k)) | |
{ | |
pit_flag = 0; | |
/* range for closed loop pitch search in 3rd subframe */ | |
T0_min = (T_op2 - 8); | |
if (T0_min < PIT_MIN) | |
{ | |
T0_min = PIT_MIN; | |
} | |
T0_max = (T0_min + 15); | |
if (T0_max > PIT_MAX) | |
{ | |
T0_max = PIT_MAX; | |
T0_min = (T0_max - 15); | |
} | |
} | |
/*-----------------------------------------------------------------------* | |
* * | |
* Find the target vector for pitch search: * | |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * | |
* * | |
* |------| res[n] * | |
* speech[n]---| A(z) |-------- * | |
* |------| | |--------| error[n] |------| * | |
* zero -- (-)--| 1/A(z) |-----------| W(z) |-- target * | |
* exc |--------| |------| * | |
* * | |
* Instead of subtracting the zero-input response of filters from * | |
* the weighted input speech, the above configuration is used to * | |
* compute the target vector. * | |
* * | |
*-----------------------------------------------------------------------*/ | |
for (i = 0; i < M; i++) | |
{ | |
error[i] = vo_sub(speech[i + i_subfr - M], st->mem_syn[i]); | |
} | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Residu_opt(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR); | |
#else | |
Residu(p_Aq, &speech[i_subfr], &exc[i_subfr], L_SUBFR); | |
#endif | |
Syn_filt(p_Aq, &exc[i_subfr], error + M, L_SUBFR, error, 0); | |
Weight_a(p_A, Ap, GAMMA1, M); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Residu_opt(Ap, error + M, xn, L_SUBFR); | |
#else | |
Residu(Ap, error + M, xn, L_SUBFR); | |
#endif | |
Deemph2(xn, TILT_FAC, L_SUBFR, &(st->mem_w0)); | |
/*----------------------------------------------------------------------* | |
* Find approx. target in residual domain "cn[]" for inovation search. * | |
*----------------------------------------------------------------------*/ | |
/* first half: xn[] --> cn[] */ | |
Set_zero(code, M); | |
Copy(xn, code + M, L_SUBFR / 2); | |
tmp = 0; | |
Preemph2(code + M, TILT_FAC, L_SUBFR / 2, &tmp); | |
Weight_a(p_A, Ap, GAMMA1, M); | |
Syn_filt(Ap,code + M, code + M, L_SUBFR / 2, code, 0); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Residu_opt(p_Aq,code + M, cn, L_SUBFR / 2); | |
#else | |
Residu(p_Aq,code + M, cn, L_SUBFR / 2); | |
#endif | |
/* second half: res[] --> cn[] (approximated and faster) */ | |
Copy(&exc[i_subfr + (L_SUBFR / 2)], cn + (L_SUBFR / 2), L_SUBFR / 2); | |
/*---------------------------------------------------------------* | |
* Compute impulse response, h1[], of weighted synthesis filter * | |
*---------------------------------------------------------------*/ | |
Set_zero(error, M + L_SUBFR); | |
Weight_a(p_A, error + M, GAMMA1, M); | |
vo_p0 = error+M; | |
vo_p3 = h1; | |
for (i = 0; i < L_SUBFR; i++) | |
{ | |
L_tmp = *vo_p0 << 14; /* x4 (Q12 to Q14) */ | |
vo_p1 = p_Aq + 1; | |
vo_p2 = vo_p0-1; | |
for (j = 1; j <= M/4; j++) | |
{ | |
L_tmp -= *vo_p1++ * *vo_p2--; | |
L_tmp -= *vo_p1++ * *vo_p2--; | |
L_tmp -= *vo_p1++ * *vo_p2--; | |
L_tmp -= *vo_p1++ * *vo_p2--; | |
} | |
*vo_p3++ = *vo_p0++ = vo_round((L_tmp <<4)); | |
} | |
/* deemph without division by 2 -> Q14 to Q15 */ | |
tmp = 0; | |
Deemph2(h1, TILT_FAC, L_SUBFR, &tmp); /* h1 in Q14 */ | |
/* h2 in Q12 for codebook search */ | |
Copy(h1, h2, L_SUBFR); | |
/*---------------------------------------------------------------* | |
* scale xn[] and h1[] to avoid overflow in dot_product12() * | |
*---------------------------------------------------------------*/ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Scale_sig_opt(h2, L_SUBFR, -2); | |
Scale_sig_opt(xn, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */ | |
Scale_sig_opt(h1, L_SUBFR, 1 + shift); /* set h1[] in Q15 with scaling for convolution */ | |
#else | |
Scale_sig(h2, L_SUBFR, -2); | |
Scale_sig(xn, L_SUBFR, shift); /* scaling of xn[] to limit dynamic at 12 bits */ | |
Scale_sig(h1, L_SUBFR, 1 + shift); /* set h1[] in Q15 with scaling for convolution */ | |
#endif | |
/*----------------------------------------------------------------------* | |
* Closed-loop fractional pitch search * | |
*----------------------------------------------------------------------*/ | |
/* find closed loop fractional pitch lag */ | |
if(*ser_size <= NBBITS_9k) | |
{ | |
T0 = Pitch_fr4(&exc[i_subfr], xn, h1, T0_min, T0_max, &T0_frac, | |
pit_flag, PIT_MIN, PIT_FR1_8b, L_SUBFR); | |
/* encode pitch lag */ | |
if (pit_flag == 0) /* if 1st/3rd subframe */ | |
{ | |
/*--------------------------------------------------------------* | |
* The pitch range for the 1st/3rd subframe is encoded with * | |
* 8 bits and is divided as follows: * | |
* PIT_MIN to PIT_FR1-1 resolution 1/2 (frac = 0 or 2) * | |
* PIT_FR1 to PIT_MAX resolution 1 (frac = 0) * | |
*--------------------------------------------------------------*/ | |
if (T0 < PIT_FR1_8b) | |
{ | |
index = ((T0 << 1) + (T0_frac >> 1) - (PIT_MIN<<1)); | |
} else | |
{ | |
index = ((T0 - PIT_FR1_8b) + ((PIT_FR1_8b - PIT_MIN)*2)); | |
} | |
Parm_serial(index, 8, &prms); | |
/* find T0_min and T0_max for subframe 2 and 4 */ | |
T0_min = (T0 - 8); | |
if (T0_min < PIT_MIN) | |
{ | |
T0_min = PIT_MIN; | |
} | |
T0_max = T0_min + 15; | |
if (T0_max > PIT_MAX) | |
{ | |
T0_max = PIT_MAX; | |
T0_min = (T0_max - 15); | |
} | |
} else | |
{ /* if subframe 2 or 4 */ | |
/*--------------------------------------------------------------* | |
* The pitch range for subframe 2 or 4 is encoded with 5 bits: * | |
* T0_min to T0_max resolution 1/2 (frac = 0 or 2) * | |
*--------------------------------------------------------------*/ | |
i = (T0 - T0_min); | |
index = (i << 1) + (T0_frac >> 1); | |
Parm_serial(index, 5, &prms); | |
} | |
} else | |
{ | |
T0 = Pitch_fr4(&exc[i_subfr], xn, h1, T0_min, T0_max, &T0_frac, | |
pit_flag, PIT_FR2, PIT_FR1_9b, L_SUBFR); | |
/* encode pitch lag */ | |
if (pit_flag == 0) /* if 1st/3rd subframe */ | |
{ | |
/*--------------------------------------------------------------* | |
* The pitch range for the 1st/3rd subframe is encoded with * | |
* 9 bits and is divided as follows: * | |
* PIT_MIN to PIT_FR2-1 resolution 1/4 (frac = 0,1,2 or 3) * | |
* PIT_FR2 to PIT_FR1-1 resolution 1/2 (frac = 0 or 1) * | |
* PIT_FR1 to PIT_MAX resolution 1 (frac = 0) * | |
*--------------------------------------------------------------*/ | |
if (T0 < PIT_FR2) | |
{ | |
index = ((T0 << 2) + T0_frac) - (PIT_MIN << 2); | |
} else if(T0 < PIT_FR1_9b) | |
{ | |
index = ((((T0 << 1) + (T0_frac >> 1)) - (PIT_FR2<<1)) + ((PIT_FR2 - PIT_MIN)<<2)); | |
} else | |
{ | |
index = (((T0 - PIT_FR1_9b) + ((PIT_FR2 - PIT_MIN)<<2)) + ((PIT_FR1_9b - PIT_FR2)<<1)); | |
} | |
Parm_serial(index, 9, &prms); | |
/* find T0_min and T0_max for subframe 2 and 4 */ | |
T0_min = (T0 - 8); | |
if (T0_min < PIT_MIN) | |
{ | |
T0_min = PIT_MIN; | |
} | |
T0_max = T0_min + 15; | |
if (T0_max > PIT_MAX) | |
{ | |
T0_max = PIT_MAX; | |
T0_min = (T0_max - 15); | |
} | |
} else | |
{ /* if subframe 2 or 4 */ | |
/*--------------------------------------------------------------* | |
* The pitch range for subframe 2 or 4 is encoded with 6 bits: * | |
* T0_min to T0_max resolution 1/4 (frac = 0,1,2 or 3) * | |
*--------------------------------------------------------------*/ | |
i = (T0 - T0_min); | |
index = (i << 2) + T0_frac; | |
Parm_serial(index, 6, &prms); | |
} | |
} | |
/*-----------------------------------------------------------------* | |
* Gain clipping test to avoid unstable synthesis on frame erasure * | |
*-----------------------------------------------------------------*/ | |
clip_gain = 0; | |
if((st->gp_clip[0] < 154) && (st->gp_clip[1] > 14746)) | |
clip_gain = 1; | |
/*-----------------------------------------------------------------* | |
* - find unity gain pitch excitation (adaptive codebook entry) * | |
* with fractional interpolation. * | |
* - find filtered pitch exc. y1[]=exc[] convolved with h1[]) * | |
* - compute pitch gain1 * | |
*-----------------------------------------------------------------*/ | |
/* find pitch exitation */ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
pred_lt4_asm(&exc[i_subfr], T0, T0_frac, L_SUBFR + 1); | |
#else | |
Pred_lt4(&exc[i_subfr], T0, T0_frac, L_SUBFR + 1); | |
#endif | |
if (*ser_size > NBBITS_9k) | |
{ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Convolve_asm(&exc[i_subfr], h1, y1, L_SUBFR); | |
#else | |
Convolve(&exc[i_subfr], h1, y1, L_SUBFR); | |
#endif | |
gain1 = G_pitch(xn, y1, g_coeff, L_SUBFR); | |
/* clip gain if necessary to avoid problem at decoder */ | |
if ((clip_gain != 0) && (gain1 > GP_CLIP)) | |
{ | |
gain1 = GP_CLIP; | |
} | |
/* find energy of new target xn2[] */ | |
Updt_tar(xn, dn, y1, gain1, L_SUBFR); /* dn used temporary */ | |
} else | |
{ | |
gain1 = 0; | |
} | |
/*-----------------------------------------------------------------* | |
* - find pitch excitation filtered by 1st order LP filter. * | |
* - find filtered pitch exc. y2[]=exc[] convolved with h1[]) * | |
* - compute pitch gain2 * | |
*-----------------------------------------------------------------*/ | |
/* find pitch excitation with lp filter */ | |
vo_p0 = exc + i_subfr-1; | |
vo_p1 = code; | |
/* find pitch excitation with lp filter */ | |
for (i = 0; i < L_SUBFR/2; i++) | |
{ | |
L_tmp = 5898 * *vo_p0++; | |
L_tmp1 = 5898 * *vo_p0; | |
L_tmp += 20972 * *vo_p0++; | |
L_tmp1 += 20972 * *vo_p0++; | |
L_tmp1 += 5898 * *vo_p0--; | |
L_tmp += 5898 * *vo_p0; | |
*vo_p1++ = (L_tmp + 0x4000)>>15; | |
*vo_p1++ = (L_tmp1 + 0x4000)>>15; | |
} | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Convolve_asm(code, h1, y2, L_SUBFR); | |
#else | |
Convolve(code, h1, y2, L_SUBFR); | |
#endif | |
gain2 = G_pitch(xn, y2, g_coeff2, L_SUBFR); | |
/* clip gain if necessary to avoid problem at decoder */ | |
if ((clip_gain != 0) && (gain2 > GP_CLIP)) | |
{ | |
gain2 = GP_CLIP; | |
} | |
/* find energy of new target xn2[] */ | |
Updt_tar(xn, xn2, y2, gain2, L_SUBFR); | |
/*-----------------------------------------------------------------* | |
* use the best prediction (minimise quadratic error). * | |
*-----------------------------------------------------------------*/ | |
select = 0; | |
if(*ser_size > NBBITS_9k) | |
{ | |
L_tmp = 0L; | |
vo_p0 = dn; | |
vo_p1 = xn2; | |
for (i = 0; i < L_SUBFR/2; i++) | |
{ | |
L_tmp += *vo_p0 * *vo_p0; | |
vo_p0++; | |
L_tmp -= *vo_p1 * *vo_p1; | |
vo_p1++; | |
L_tmp += *vo_p0 * *vo_p0; | |
vo_p0++; | |
L_tmp -= *vo_p1 * *vo_p1; | |
vo_p1++; | |
} | |
if (L_tmp <= 0) | |
{ | |
select = 1; | |
} | |
Parm_serial(select, 1, &prms); | |
} | |
if (select == 0) | |
{ | |
/* use the lp filter for pitch excitation prediction */ | |
gain_pit = gain2; | |
Copy(code, &exc[i_subfr], L_SUBFR); | |
Copy(y2, y1, L_SUBFR); | |
Copy(g_coeff2, g_coeff, 4); | |
} else | |
{ | |
/* no filter used for pitch excitation prediction */ | |
gain_pit = gain1; | |
Copy(dn, xn2, L_SUBFR); /* target vector for codebook search */ | |
} | |
/*-----------------------------------------------------------------* | |
* - update cn[] for codebook search * | |
*-----------------------------------------------------------------*/ | |
Updt_tar(cn, cn, &exc[i_subfr], gain_pit, L_SUBFR); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Scale_sig_opt(cn, L_SUBFR, shift); /* scaling of cn[] to limit dynamic at 12 bits */ | |
#else | |
Scale_sig(cn, L_SUBFR, shift); /* scaling of cn[] to limit dynamic at 12 bits */ | |
#endif | |
/*-----------------------------------------------------------------* | |
* - include fixed-gain pitch contribution into impulse resp. h1[] * | |
*-----------------------------------------------------------------*/ | |
tmp = 0; | |
Preemph(h2, st->tilt_code, L_SUBFR, &tmp); | |
if (T0_frac > 2) | |
T0 = (T0 + 1); | |
Pit_shrp(h2, T0, PIT_SHARP, L_SUBFR); | |
/*-----------------------------------------------------------------* | |
* - Correlation between target xn2[] and impulse response h1[] * | |
* - Innovative codebook search * | |
*-----------------------------------------------------------------*/ | |
cor_h_x(h2, xn2, dn); | |
if (*ser_size <= NBBITS_7k) | |
{ | |
ACELP_2t64_fx(dn, cn, h2, code, y2, indice); | |
Parm_serial(indice[0], 12, &prms); | |
} else if(*ser_size <= NBBITS_9k) | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 20, *ser_size, indice); | |
Parm_serial(indice[0], 5, &prms); | |
Parm_serial(indice[1], 5, &prms); | |
Parm_serial(indice[2], 5, &prms); | |
Parm_serial(indice[3], 5, &prms); | |
} else if(*ser_size <= NBBITS_12k) | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 36, *ser_size, indice); | |
Parm_serial(indice[0], 9, &prms); | |
Parm_serial(indice[1], 9, &prms); | |
Parm_serial(indice[2], 9, &prms); | |
Parm_serial(indice[3], 9, &prms); | |
} else if(*ser_size <= NBBITS_14k) | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 44, *ser_size, indice); | |
Parm_serial(indice[0], 13, &prms); | |
Parm_serial(indice[1], 13, &prms); | |
Parm_serial(indice[2], 9, &prms); | |
Parm_serial(indice[3], 9, &prms); | |
} else if(*ser_size <= NBBITS_16k) | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 52, *ser_size, indice); | |
Parm_serial(indice[0], 13, &prms); | |
Parm_serial(indice[1], 13, &prms); | |
Parm_serial(indice[2], 13, &prms); | |
Parm_serial(indice[3], 13, &prms); | |
} else if(*ser_size <= NBBITS_18k) | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 64, *ser_size, indice); | |
Parm_serial(indice[0], 2, &prms); | |
Parm_serial(indice[1], 2, &prms); | |
Parm_serial(indice[2], 2, &prms); | |
Parm_serial(indice[3], 2, &prms); | |
Parm_serial(indice[4], 14, &prms); | |
Parm_serial(indice[5], 14, &prms); | |
Parm_serial(indice[6], 14, &prms); | |
Parm_serial(indice[7], 14, &prms); | |
} else if(*ser_size <= NBBITS_20k) | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 72, *ser_size, indice); | |
Parm_serial(indice[0], 10, &prms); | |
Parm_serial(indice[1], 10, &prms); | |
Parm_serial(indice[2], 2, &prms); | |
Parm_serial(indice[3], 2, &prms); | |
Parm_serial(indice[4], 10, &prms); | |
Parm_serial(indice[5], 10, &prms); | |
Parm_serial(indice[6], 14, &prms); | |
Parm_serial(indice[7], 14, &prms); | |
} else | |
{ | |
ACELP_4t64_fx(dn, cn, h2, code, y2, 88, *ser_size, indice); | |
Parm_serial(indice[0], 11, &prms); | |
Parm_serial(indice[1], 11, &prms); | |
Parm_serial(indice[2], 11, &prms); | |
Parm_serial(indice[3], 11, &prms); | |
Parm_serial(indice[4], 11, &prms); | |
Parm_serial(indice[5], 11, &prms); | |
Parm_serial(indice[6], 11, &prms); | |
Parm_serial(indice[7], 11, &prms); | |
} | |
/*-------------------------------------------------------* | |
* - Add the fixed-gain pitch contribution to code[]. * | |
*-------------------------------------------------------*/ | |
tmp = 0; | |
Preemph(code, st->tilt_code, L_SUBFR, &tmp); | |
Pit_shrp(code, T0, PIT_SHARP, L_SUBFR); | |
/*----------------------------------------------------------* | |
* - Compute the fixed codebook gain * | |
* - quantize fixed codebook gain * | |
*----------------------------------------------------------*/ | |
if(*ser_size <= NBBITS_9k) | |
{ | |
index = Q_gain2(xn, y1, Q_new + shift, y2, code, g_coeff, L_SUBFR, 6, | |
&gain_pit, &L_gain_code, clip_gain, st->qua_gain); | |
Parm_serial(index, 6, &prms); | |
} else | |
{ | |
index = Q_gain2(xn, y1, Q_new + shift, y2, code, g_coeff, L_SUBFR, 7, | |
&gain_pit, &L_gain_code, clip_gain, st->qua_gain); | |
Parm_serial(index, 7, &prms); | |
} | |
/* test quantized gain of pitch for pitch clipping algorithm */ | |
Gp_clip_test_gain_pit(gain_pit, st->gp_clip); | |
L_tmp = L_shl(L_gain_code, Q_new); | |
gain_code = extract_h(L_add(L_tmp, 0x8000)); | |
/*----------------------------------------------------------* | |
* Update parameters for the next subframe. * | |
* - tilt of code: 0.0 (unvoiced) to 0.5 (voiced) * | |
*----------------------------------------------------------*/ | |
/* find voice factor in Q15 (1=voiced, -1=unvoiced) */ | |
Copy(&exc[i_subfr], exc2, L_SUBFR); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Scale_sig_opt(exc2, L_SUBFR, shift); | |
#else | |
Scale_sig(exc2, L_SUBFR, shift); | |
#endif | |
voice_fac = voice_factor(exc2, shift, gain_pit, code, gain_code, L_SUBFR); | |
/* tilt of code for next subframe: 0.5=voiced, 0=unvoiced */ | |
st->tilt_code = ((voice_fac >> 2) + 8192); | |
/*------------------------------------------------------* | |
* - Update filter's memory "mem_w0" for finding the * | |
* target vector in the next subframe. * | |
* - Find the total excitation * | |
* - Find synthesis speech to update mem_syn[]. * | |
*------------------------------------------------------*/ | |
/* y2 in Q9, gain_pit in Q14 */ | |
L_tmp = (gain_code * y2[L_SUBFR - 1])<<1; | |
L_tmp = L_shl(L_tmp, (5 + shift)); | |
L_tmp = L_negate(L_tmp); | |
L_tmp += (xn[L_SUBFR - 1] * 16384)<<1; | |
L_tmp -= (y1[L_SUBFR - 1] * gain_pit)<<1; | |
L_tmp = L_shl(L_tmp, (1 - shift)); | |
st->mem_w0 = extract_h(L_add(L_tmp, 0x8000)); | |
if (*ser_size >= NBBITS_24k) | |
Copy(&exc[i_subfr], exc2, L_SUBFR); | |
for (i = 0; i < L_SUBFR; i++) | |
{ | |
/* code in Q9, gain_pit in Q14 */ | |
L_tmp = (gain_code * code[i])<<1; | |
L_tmp = (L_tmp << 5); | |
L_tmp += (exc[i + i_subfr] * gain_pit)<<1; | |
L_tmp = L_shl2(L_tmp, 1); | |
exc[i + i_subfr] = extract_h(L_add(L_tmp, 0x8000)); | |
} | |
Syn_filt(p_Aq,&exc[i_subfr], synth, L_SUBFR, st->mem_syn, 1); | |
if(*ser_size >= NBBITS_24k) | |
{ | |
/*------------------------------------------------------------* | |
* phase dispersion to enhance noise in low bit rate * | |
*------------------------------------------------------------*/ | |
/* L_gain_code in Q16 */ | |
VO_L_Extract(L_gain_code, &gain_code, &gain_code_lo); | |
/*------------------------------------------------------------* | |
* noise enhancer * | |
* ~~~~~~~~~~~~~~ * | |
* - Enhance excitation on noise. (modify gain of code) * | |
* If signal is noisy and LPC filter is stable, move gain * | |
* of code 1.5 dB toward gain of code threshold. * | |
* This decrease by 3 dB noise energy variation. * | |
*------------------------------------------------------------*/ | |
tmp = (16384 - (voice_fac >> 1)); /* 1=unvoiced, 0=voiced */ | |
fac = vo_mult(stab_fac, tmp); | |
L_tmp = L_gain_code; | |
if(L_tmp < st->L_gc_thres) | |
{ | |
L_tmp = vo_L_add(L_tmp, Mpy_32_16(gain_code, gain_code_lo, 6226)); | |
if(L_tmp > st->L_gc_thres) | |
{ | |
L_tmp = st->L_gc_thres; | |
} | |
} else | |
{ | |
L_tmp = Mpy_32_16(gain_code, gain_code_lo, 27536); | |
if(L_tmp < st->L_gc_thres) | |
{ | |
L_tmp = st->L_gc_thres; | |
} | |
} | |
st->L_gc_thres = L_tmp; | |
L_gain_code = Mpy_32_16(gain_code, gain_code_lo, (32767 - fac)); | |
VO_L_Extract(L_tmp, &gain_code, &gain_code_lo); | |
L_gain_code = vo_L_add(L_gain_code, Mpy_32_16(gain_code, gain_code_lo, fac)); | |
/*------------------------------------------------------------* | |
* pitch enhancer * | |
* ~~~~~~~~~~~~~~ * | |
* - Enhance excitation on voice. (HP filtering of code) * | |
* On voiced signal, filtering of code by a smooth fir HP * | |
* filter to decrease energy of code in low frequency. * | |
*------------------------------------------------------------*/ | |
tmp = ((voice_fac >> 3) + 4096); /* 0.25=voiced, 0=unvoiced */ | |
L_tmp = L_deposit_h(code[0]); | |
L_tmp -= (code[1] * tmp)<<1; | |
code2[0] = vo_round(L_tmp); | |
for (i = 1; i < L_SUBFR - 1; i++) | |
{ | |
L_tmp = L_deposit_h(code[i]); | |
L_tmp -= (code[i + 1] * tmp)<<1; | |
L_tmp -= (code[i - 1] * tmp)<<1; | |
code2[i] = vo_round(L_tmp); | |
} | |
L_tmp = L_deposit_h(code[L_SUBFR - 1]); | |
L_tmp -= (code[L_SUBFR - 2] * tmp)<<1; | |
code2[L_SUBFR - 1] = vo_round(L_tmp); | |
/* build excitation */ | |
gain_code = vo_round(L_shl(L_gain_code, Q_new)); | |
for (i = 0; i < L_SUBFR; i++) | |
{ | |
L_tmp = (code2[i] * gain_code)<<1; | |
L_tmp = (L_tmp << 5); | |
L_tmp += (exc2[i] * gain_pit)<<1; | |
L_tmp = (L_tmp << 1); | |
exc2[i] = vo_round(L_tmp); | |
} | |
corr_gain = synthesis(p_Aq, exc2, Q_new, &speech16k[i_subfr * 5 / 4], st); | |
Parm_serial(corr_gain, 4, &prms); | |
} | |
p_A += (M + 1); | |
p_Aq += (M + 1); | |
} /* end of subframe loop */ | |
/*--------------------------------------------------* | |
* Update signal for next frame. * | |
* -> save past of speech[], wsp[] and exc[]. * | |
*--------------------------------------------------*/ | |
Copy(&old_speech[L_FRAME], st->old_speech, L_TOTAL - L_FRAME); | |
Copy(&old_wsp[L_FRAME / OPL_DECIM], st->old_wsp, PIT_MAX / OPL_DECIM); | |
Copy(&old_exc[L_FRAME], st->old_exc, PIT_MAX + L_INTERPOL); | |
return; | |
} | |
/*-----------------------------------------------------* | |
* Function synthesis() * | |
* * | |
* Synthesis of signal at 16kHz with HF extension. * | |
* * | |
*-----------------------------------------------------*/ | |
static Word16 synthesis( | |
Word16 Aq[], /* A(z) : quantized Az */ | |
Word16 exc[], /* (i) : excitation at 12kHz */ | |
Word16 Q_new, /* (i) : scaling performed on exc */ | |
Word16 synth16k[], /* (o) : 16kHz synthesis signal */ | |
Coder_State * st /* (i/o) : State structure */ | |
) | |
{ | |
Word16 fac, tmp, exp; | |
Word16 ener, exp_ener; | |
Word32 L_tmp, i; | |
Word16 synth_hi[M + L_SUBFR], synth_lo[M + L_SUBFR]; | |
Word16 synth[L_SUBFR]; | |
Word16 HF[L_SUBFR16k]; /* High Frequency vector */ | |
Word16 Ap[M + 1]; | |
Word16 HF_SP[L_SUBFR16k]; /* High Frequency vector (from original signal) */ | |
Word16 HP_est_gain, HP_calc_gain, HP_corr_gain; | |
Word16 dist_min, dist; | |
Word16 HP_gain_ind = 0; | |
Word16 gain1, gain2; | |
Word16 weight1, weight2; | |
/*------------------------------------------------------------* | |
* speech synthesis * | |
* ~~~~~~~~~~~~~~~~ * | |
* - Find synthesis speech corresponding to exc2[]. * | |
* - Perform fixed deemphasis and hp 50hz filtering. * | |
* - Oversampling from 12.8kHz to 16kHz. * | |
*------------------------------------------------------------*/ | |
Copy(st->mem_syn_hi, synth_hi, M); | |
Copy(st->mem_syn_lo, synth_lo, M); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Syn_filt_32_asm(Aq, M, exc, Q_new, synth_hi + M, synth_lo + M, L_SUBFR); | |
#else | |
Syn_filt_32(Aq, M, exc, Q_new, synth_hi + M, synth_lo + M, L_SUBFR); | |
#endif | |
Copy(synth_hi + L_SUBFR, st->mem_syn_hi, M); | |
Copy(synth_lo + L_SUBFR, st->mem_syn_lo, M); | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Deemph_32_asm(synth_hi + M, synth_lo + M, synth, &(st->mem_deemph)); | |
#else | |
Deemph_32(synth_hi + M, synth_lo + M, synth, PREEMPH_FAC, L_SUBFR, &(st->mem_deemph)); | |
#endif | |
HP50_12k8(synth, L_SUBFR, st->mem_sig_out); | |
/* Original speech signal as reference for high band gain quantisation */ | |
for (i = 0; i < L_SUBFR16k; i++) | |
{ | |
HF_SP[i] = synth16k[i]; | |
} | |
/*------------------------------------------------------* | |
* HF noise synthesis * | |
* ~~~~~~~~~~~~~~~~~~ * | |
* - Generate HF noise between 5.5 and 7.5 kHz. * | |
* - Set energy of noise according to synthesis tilt. * | |
* tilt > 0.8 ==> - 14 dB (voiced) * | |
* tilt 0.5 ==> - 6 dB (voiced or noise) * | |
* tilt < 0.0 ==> 0 dB (noise) * | |
*------------------------------------------------------*/ | |
/* generate white noise vector */ | |
for (i = 0; i < L_SUBFR16k; i++) | |
{ | |
HF[i] = Random(&(st->seed2))>>3; | |
} | |
/* energy of excitation */ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Scale_sig_opt(exc, L_SUBFR, -3); | |
Q_new = Q_new - 3; | |
ener = extract_h(Dot_product12_asm(exc, exc, L_SUBFR, &exp_ener)); | |
#else | |
Scale_sig(exc, L_SUBFR, -3); | |
Q_new = Q_new - 3; | |
ener = extract_h(Dot_product12(exc, exc, L_SUBFR, &exp_ener)); | |
#endif | |
exp_ener = exp_ener - (Q_new + Q_new); | |
/* set energy of white noise to energy of excitation */ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
tmp = extract_h(Dot_product12_asm(HF, HF, L_SUBFR16k, &exp)); | |
#else | |
tmp = extract_h(Dot_product12(HF, HF, L_SUBFR16k, &exp)); | |
#endif | |
if(tmp > ener) | |
{ | |
tmp = (tmp >> 1); /* Be sure tmp < ener */ | |
exp = (exp + 1); | |
} | |
L_tmp = L_deposit_h(div_s(tmp, ener)); /* result is normalized */ | |
exp = (exp - exp_ener); | |
Isqrt_n(&L_tmp, &exp); | |
L_tmp = L_shl(L_tmp, (exp + 1)); /* L_tmp x 2, L_tmp in Q31 */ | |
tmp = extract_h(L_tmp); /* tmp = 2 x sqrt(ener_exc/ener_hf) */ | |
for (i = 0; i < L_SUBFR16k; i++) | |
{ | |
HF[i] = vo_mult(HF[i], tmp); | |
} | |
/* find tilt of synthesis speech (tilt: 1=voiced, -1=unvoiced) */ | |
HP400_12k8(synth, L_SUBFR, st->mem_hp400); | |
L_tmp = 1L; | |
for (i = 0; i < L_SUBFR; i++) | |
L_tmp += (synth[i] * synth[i])<<1; | |
exp = norm_l(L_tmp); | |
ener = extract_h(L_tmp << exp); /* ener = r[0] */ | |
L_tmp = 1L; | |
for (i = 1; i < L_SUBFR; i++) | |
L_tmp +=(synth[i] * synth[i - 1])<<1; | |
tmp = extract_h(L_tmp << exp); /* tmp = r[1] */ | |
if (tmp > 0) | |
{ | |
fac = div_s(tmp, ener); | |
} else | |
{ | |
fac = 0; | |
} | |
/* modify energy of white noise according to synthesis tilt */ | |
gain1 = 32767 - fac; | |
gain2 = vo_mult(gain1, 20480); | |
gain2 = shl(gain2, 1); | |
if (st->vad_hist > 0) | |
{ | |
weight1 = 0; | |
weight2 = 32767; | |
} else | |
{ | |
weight1 = 32767; | |
weight2 = 0; | |
} | |
tmp = vo_mult(weight1, gain1); | |
tmp = add1(tmp, vo_mult(weight2, gain2)); | |
if (tmp != 0) | |
{ | |
tmp = (tmp + 1); | |
} | |
HP_est_gain = tmp; | |
if(HP_est_gain < 3277) | |
{ | |
HP_est_gain = 3277; /* 0.1 in Q15 */ | |
} | |
/* synthesis of noise: 4.8kHz..5.6kHz --> 6kHz..7kHz */ | |
Weight_a(Aq, Ap, 19661, M); /* fac=0.6 */ | |
#ifdef ASM_OPT /* asm optimization branch */ | |
Syn_filt_asm(Ap, HF, HF, st->mem_syn_hf); | |
/* noise High Pass filtering (1ms of delay) */ | |
Filt_6k_7k_asm(HF, L_SUBFR16k, st->mem_hf); | |
/* filtering of the original signal */ | |
Filt_6k_7k_asm(HF_SP, L_SUBFR16k, st->mem_hf2); | |
/* check the gain difference */ | |
Scale_sig_opt(HF_SP, L_SUBFR16k, -1); | |
ener = extract_h(Dot_product12_asm(HF_SP, HF_SP, L_SUBFR16k, &exp_ener)); | |
/* set energy of white noise to energy of excitation */ | |
tmp = extract_h(Dot_product12_asm(HF, HF, L_SUBFR16k, &exp)); | |
#else | |
Syn_filt(Ap, HF, HF, L_SUBFR16k, st->mem_syn_hf, 1); | |
/* noise High Pass filtering (1ms of delay) */ | |
Filt_6k_7k(HF, L_SUBFR16k, st->mem_hf); | |
/* filtering of the original signal */ | |
Filt_6k_7k(HF_SP, L_SUBFR16k, st->mem_hf2); | |
/* check the gain difference */ | |
Scale_sig(HF_SP, L_SUBFR16k, -1); | |
ener = extract_h(Dot_product12(HF_SP, HF_SP, L_SUBFR16k, &exp_ener)); | |
/* set energy of white noise to energy of excitation */ | |
tmp = extract_h(Dot_product12(HF, HF, L_SUBFR16k, &exp)); | |
#endif | |
if (tmp > ener) | |
{ | |
tmp = (tmp >> 1); /* Be sure tmp < ener */ | |
exp = (exp + 1); | |
} | |
L_tmp = L_deposit_h(div_s(tmp, ener)); /* result is normalized */ | |
exp = vo_sub(exp, exp_ener); | |
Isqrt_n(&L_tmp, &exp); | |
L_tmp = L_shl(L_tmp, exp); /* L_tmp, L_tmp in Q31 */ | |
HP_calc_gain = extract_h(L_tmp); /* tmp = sqrt(ener_input/ener_hf) */ | |
/* st->gain_alpha *= st->dtx_encSt->dtxHangoverCount/7 */ | |
L_tmp = (vo_L_mult(st->dtx_encSt->dtxHangoverCount, 4681) << 15); | |
st->gain_alpha = vo_mult(st->gain_alpha, extract_h(L_tmp)); | |
if(st->dtx_encSt->dtxHangoverCount > 6) | |
st->gain_alpha = 32767; | |
HP_est_gain = HP_est_gain >> 1; /* From Q15 to Q14 */ | |
HP_corr_gain = add1(vo_mult(HP_calc_gain, st->gain_alpha), vo_mult((32767 - st->gain_alpha), HP_est_gain)); | |
/* Quantise the correction gain */ | |
dist_min = 32767; | |
for (i = 0; i < 16; i++) | |
{ | |
dist = vo_mult((HP_corr_gain - HP_gain[i]), (HP_corr_gain - HP_gain[i])); | |
if (dist_min > dist) | |
{ | |
dist_min = dist; | |
HP_gain_ind = i; | |
} | |
} | |
HP_corr_gain = HP_gain[HP_gain_ind]; | |
/* return the quantised gain index when using the highest mode, otherwise zero */ | |
return (HP_gain_ind); | |
} | |
/************************************************* | |
* | |
* Breif: Codec main function | |
* | |
**************************************************/ | |
int AMR_Enc_Encode(HAMRENC hCodec) | |
{ | |
Word32 i; | |
Coder_State *gData = (Coder_State*)hCodec; | |
Word16 *signal; | |
Word16 packed_size = 0; | |
Word16 prms[NB_BITS_MAX]; | |
Word16 coding_mode = 0, nb_bits, allow_dtx, mode, reset_flag; | |
mode = gData->mode; | |
coding_mode = gData->mode; | |
nb_bits = nb_of_bits[mode]; | |
signal = (Word16 *)gData->inputStream; | |
allow_dtx = gData->allow_dtx; | |
/* check for homing frame */ | |
reset_flag = encoder_homing_frame_test(signal); | |
for (i = 0; i < L_FRAME16k; i++) /* Delete the 2 LSBs (14-bit input) */ | |
{ | |
*(signal + i) = (Word16) (*(signal + i) & 0xfffC); | |
} | |
coder(&coding_mode, signal, prms, &nb_bits, gData, allow_dtx); | |
packed_size = PackBits(prms, coding_mode, mode, gData); | |
if (reset_flag != 0) | |
{ | |
Reset_encoder(gData, 1); | |
} | |
return packed_size; | |
} | |
/*************************************************************************** | |
* | |
*Brief: Codec API function --- Initialize the codec and return a codec handle | |
* | |
***************************************************************************/ | |
VO_U32 VO_API voAMRWB_Init(VO_HANDLE * phCodec, /* o: the audio codec handle */ | |
VO_AUDIO_CODINGTYPE vType, /* i: Codec Type ID */ | |
VO_CODEC_INIT_USERDATA * pUserData /* i: init Parameters */ | |
) | |
{ | |
Coder_State *st; | |
FrameStream *stream; | |
#ifdef USE_DEAULT_MEM | |
VO_MEM_OPERATOR voMemoprator; | |
#endif | |
VO_MEM_OPERATOR *pMemOP; | |
int interMem = 0; | |
if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL ) | |
{ | |
#ifdef USE_DEAULT_MEM | |
voMemoprator.Alloc = cmnMemAlloc; | |
voMemoprator.Copy = cmnMemCopy; | |
voMemoprator.Free = cmnMemFree; | |
voMemoprator.Set = cmnMemSet; | |
voMemoprator.Check = cmnMemCheck; | |
interMem = 1; | |
pMemOP = &voMemoprator; | |
#else | |
*phCodec = NULL; | |
return VO_ERR_INVALID_ARG; | |
#endif | |
} | |
else | |
{ | |
pMemOP = (VO_MEM_OPERATOR *)pUserData->memData; | |
} | |
/*-------------------------------------------------------------------------* | |
* Memory allocation for coder state. * | |
*-------------------------------------------------------------------------*/ | |
if ((st = (Coder_State *)mem_malloc(pMemOP, sizeof(Coder_State), 32, VO_INDEX_ENC_AMRWB)) == NULL) | |
{ | |
return VO_ERR_OUTOF_MEMORY; | |
} | |
st->vadSt = NULL; | |
st->dtx_encSt = NULL; | |
st->sid_update_counter = 3; | |
st->sid_handover_debt = 0; | |
st->prev_ft = TX_SPEECH; | |
st->inputStream = NULL; | |
st->inputSize = 0; | |
/* Default setting */ | |
st->mode = VOAMRWB_MD2385; /* bit rate 23.85kbps */ | |
st->frameType = VOAMRWB_RFC3267; /* frame type: RFC3267 */ | |
st->allow_dtx = 0; /* disable DTX mode */ | |
st->outputStream = NULL; | |
st->outputSize = 0; | |
st->stream = (FrameStream *)mem_malloc(pMemOP, sizeof(FrameStream), 32, VO_INDEX_ENC_AMRWB); | |
if(st->stream == NULL) | |
return VO_ERR_OUTOF_MEMORY; | |
st->stream->frame_ptr = (unsigned char *)mem_malloc(pMemOP, Frame_Maxsize, 32, VO_INDEX_ENC_AMRWB); | |
if(st->stream->frame_ptr == NULL) | |
return VO_ERR_OUTOF_MEMORY; | |
stream = st->stream; | |
voAWB_InitFrameBuffer(stream); | |
wb_vad_init(&(st->vadSt), pMemOP); | |
dtx_enc_init(&(st->dtx_encSt), isf_init, pMemOP); | |
Reset_encoder((void *) st, 1); | |
if(interMem) | |
{ | |
st->voMemoprator.Alloc = cmnMemAlloc; | |
st->voMemoprator.Copy = cmnMemCopy; | |
st->voMemoprator.Free = cmnMemFree; | |
st->voMemoprator.Set = cmnMemSet; | |
st->voMemoprator.Check = cmnMemCheck; | |
pMemOP = &st->voMemoprator; | |
} | |
st->pvoMemop = pMemOP; | |
*phCodec = (void *) st; | |
return VO_ERR_NONE; | |
} | |
/********************************************************************************** | |
* | |
* Brief: Codec API function: Input PCM data | |
* | |
***********************************************************************************/ | |
VO_U32 VO_API voAMRWB_SetInputData( | |
VO_HANDLE hCodec, /* i/o: The codec handle which was created by Init function */ | |
VO_CODECBUFFER * pInput /* i: The input buffer parameter */ | |
) | |
{ | |
Coder_State *gData; | |
FrameStream *stream; | |
if(NULL == hCodec) | |
{ | |
return VO_ERR_INVALID_ARG; | |
} | |
gData = (Coder_State *)hCodec; | |
stream = gData->stream; | |
if(NULL == pInput || NULL == pInput->Buffer || 0 > pInput->Length) | |
{ | |
return VO_ERR_INVALID_ARG; | |
} | |
stream->set_ptr = pInput->Buffer; | |
stream->set_len = pInput->Length; | |
stream->frame_ptr = stream->frame_ptr_bk; | |
stream->used_len = 0; | |
return VO_ERR_NONE; | |
} | |
/************************************************************************************** | |
* | |
* Brief: Codec API function: Get the compression audio data frame by frame | |
* | |
***************************************************************************************/ | |
VO_U32 VO_API voAMRWB_GetOutputData( | |
VO_HANDLE hCodec, /* i: The Codec Handle which was created by Init function*/ | |
VO_CODECBUFFER * pOutput, /* o: The output audio data */ | |
VO_AUDIO_OUTPUTINFO * pAudioFormat /* o: The encoder module filled audio format and used the input size*/ | |
) | |
{ | |
Coder_State* gData = (Coder_State*)hCodec; | |
VO_MEM_OPERATOR *pMemOP; | |
FrameStream *stream = (FrameStream *)gData->stream; | |
pMemOP = (VO_MEM_OPERATOR *)gData->pvoMemop; | |
if(stream->framebuffer_len < Frame_MaxByte) /* check the work buffer len */ | |
{ | |
stream->frame_storelen = stream->framebuffer_len; | |
if(stream->frame_storelen) | |
{ | |
pMemOP->Copy(VO_INDEX_ENC_AMRWB, stream->frame_ptr_bk , stream->frame_ptr , stream->frame_storelen); | |
} | |
if(stream->set_len > 0) | |
{ | |
voAWB_UpdateFrameBuffer(stream, pMemOP); | |
} | |
if(stream->framebuffer_len < Frame_MaxByte) | |
{ | |
if(pAudioFormat) | |
pAudioFormat->InputUsed = stream->used_len; | |
return VO_ERR_INPUT_BUFFER_SMALL; | |
} | |
} | |
gData->inputStream = stream->frame_ptr; | |
gData->outputStream = (unsigned short*)pOutput->Buffer; | |
gData->outputSize = AMR_Enc_Encode(gData); /* encoder main function */ | |
pOutput->Length = gData->outputSize; /* get the output buffer length */ | |
stream->frame_ptr += 640; /* update the work buffer ptr */ | |
stream->framebuffer_len -= 640; | |
if(pAudioFormat) /* return output audio information */ | |
{ | |
pAudioFormat->Format.Channels = 1; | |
pAudioFormat->Format.SampleRate = 8000; | |
pAudioFormat->Format.SampleBits = 16; | |
pAudioFormat->InputUsed = stream->used_len; | |
} | |
return VO_ERR_NONE; | |
} | |
/************************************************************************* | |
* | |
* Brief: Codec API function---set the data by specified parameter ID | |
* | |
*************************************************************************/ | |
VO_U32 VO_API voAMRWB_SetParam( | |
VO_HANDLE hCodec, /* i/o: The Codec Handle which was created by Init function */ | |
VO_S32 uParamID, /* i: The param ID */ | |
VO_PTR pData /* i: The param value depend on the ID */ | |
) | |
{ | |
Coder_State* gData = (Coder_State*)hCodec; | |
FrameStream *stream = (FrameStream *)(gData->stream); | |
int *lValue = (int*)pData; | |
switch(uParamID) | |
{ | |
/* setting AMR-WB frame type*/ | |
case VO_PID_AMRWB_FRAMETYPE: | |
if(*lValue < VOAMRWB_DEFAULT || *lValue > VOAMRWB_RFC3267) | |
return VO_ERR_WRONG_PARAM_ID; | |
gData->frameType = *lValue; | |
break; | |
/* setting AMR-WB bit rate */ | |
case VO_PID_AMRWB_MODE: | |
{ | |
if(*lValue < VOAMRWB_MD66 || *lValue > VOAMRWB_MD2385) | |
return VO_ERR_WRONG_PARAM_ID; | |
gData->mode = *lValue; | |
} | |
break; | |
/* enable or disable DTX mode */ | |
case VO_PID_AMRWB_DTX: | |
gData->allow_dtx = (Word16)(*lValue); | |
break; | |
case VO_PID_COMMON_HEADDATA: | |
break; | |
/* flush the work buffer */ | |
case VO_PID_COMMON_FLUSH: | |
stream->set_ptr = NULL; | |
stream->frame_storelen = 0; | |
stream->framebuffer_len = 0; | |
stream->set_len = 0; | |
break; | |
default: | |
return VO_ERR_WRONG_PARAM_ID; | |
} | |
return VO_ERR_NONE; | |
} | |
/************************************************************************** | |
* | |
*Brief: Codec API function---Get the data by specified parameter ID | |
* | |
***************************************************************************/ | |
VO_U32 VO_API voAMRWB_GetParam( | |
VO_HANDLE hCodec, /* i: The Codec Handle which was created by Init function */ | |
VO_S32 uParamID, /* i: The param ID */ | |
VO_PTR pData /* o: The param value depend on the ID */ | |
) | |
{ | |
int temp; | |
Coder_State* gData = (Coder_State*)hCodec; | |
if (gData==NULL) | |
return VO_ERR_INVALID_ARG; | |
switch(uParamID) | |
{ | |
/* output audio format */ | |
case VO_PID_AMRWB_FORMAT: | |
{ | |
VO_AUDIO_FORMAT* fmt = (VO_AUDIO_FORMAT*)pData; | |
fmt->Channels = 1; | |
fmt->SampleRate = 16000; | |
fmt->SampleBits = 16; | |
break; | |
} | |
/* output audio channel number */ | |
case VO_PID_AMRWB_CHANNELS: | |
temp = 1; | |
pData = (void *)(&temp); | |
break; | |
/* output audio sample rate */ | |
case VO_PID_AMRWB_SAMPLERATE: | |
temp = 16000; | |
pData = (void *)(&temp); | |
break; | |
/* output audio frame type */ | |
case VO_PID_AMRWB_FRAMETYPE: | |
temp = gData->frameType; | |
pData = (void *)(&temp); | |
break; | |
/* output audio bit rate */ | |
case VO_PID_AMRWB_MODE: | |
temp = gData->mode; | |
pData = (void *)(&temp); | |
break; | |
default: | |
return VO_ERR_WRONG_PARAM_ID; | |
} | |
return VO_ERR_NONE; | |
} | |
/*********************************************************************************** | |
* | |
* Brief: Codec API function---Release the codec after all encoder operations are done | |
* | |
*************************************************************************************/ | |
VO_U32 VO_API voAMRWB_Uninit(VO_HANDLE hCodec /* i/o: Codec handle pointer */ | |
) | |
{ | |
Coder_State* gData = (Coder_State*)hCodec; | |
VO_MEM_OPERATOR *pMemOP; | |
pMemOP = gData->pvoMemop; | |
if(hCodec) | |
{ | |
if(gData->stream) | |
{ | |
if(gData->stream->frame_ptr_bk) | |
{ | |
mem_free(pMemOP, gData->stream->frame_ptr_bk, VO_INDEX_ENC_AMRWB); | |
gData->stream->frame_ptr_bk = NULL; | |
} | |
mem_free(pMemOP, gData->stream, VO_INDEX_ENC_AMRWB); | |
gData->stream = NULL; | |
} | |
wb_vad_exit(&(((Coder_State *) gData)->vadSt), pMemOP); | |
dtx_enc_exit(&(((Coder_State *) gData)->dtx_encSt), pMemOP); | |
mem_free(pMemOP, hCodec, VO_INDEX_ENC_AMRWB); | |
hCodec = NULL; | |
} | |
return VO_ERR_NONE; | |
} | |
/******************************************************************************** | |
* | |
* Brief: voGetAMRWBEncAPI gets the API handle of the codec | |
* | |
********************************************************************************/ | |
VO_S32 VO_API voGetAMRWBEncAPI( | |
VO_AUDIO_CODECAPI * pEncHandle /* i/o: Codec handle pointer */ | |
) | |
{ | |
if(NULL == pEncHandle) | |
return VO_ERR_INVALID_ARG; | |
pEncHandle->Init = voAMRWB_Init; | |
pEncHandle->SetInputData = voAMRWB_SetInputData; | |
pEncHandle->GetOutputData = voAMRWB_GetOutputData; | |
pEncHandle->SetParam = voAMRWB_SetParam; | |
pEncHandle->GetParam = voAMRWB_GetParam; | |
pEncHandle->Uninit = voAMRWB_Uninit; | |
return VO_ERR_NONE; | |
} | |
#ifdef __cplusplus | |
} | |
#endif |