FreeCalypso > hg > gsmhr-codec-ref
diff vad.c @ 0:9008dbc8ca74
import original C code from GSM 06.06
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 14 Jun 2024 23:27:16 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vad.c Fri Jun 14 23:27:16 2024 +0000 @@ -0,0 +1,1363 @@ +/**************************************************************************** + * + * TITLE: Half-Rate GSM Voice Activity Detector (VAD) Modules + * + * VERSION: 1.2 + * + * REFERENCE: Recommendation GSM 06.42 + * + ***************************************************************************/ + +/*_________________________________________________________________________ + | | + | Include Files | + |_________________________________________________________________________| +*/ + +#include "typedefs.h" +#include "mathhalf.h" +#include "mathdp31.h" +#include "vad.h" + + +/*_________________________________________________________________________ + | | + | Local Defines | + |_________________________________________________________________________| +*/ + +/*** Floating point representations of constants pth, plev and margin ***/ + +#define M_PTH 26250 +#define E_PTH 18 +#define M_PLEV 17500 +#define E_PLEV 20 +#define M_MARGIN 27343 +#define E_MARGIN 27 + +/*_________________________________________________________________________ + | | + | Static Variables | + |_________________________________________________________________________| +*/ + +static Shortword + pswRvad[9], + swNormRvad, + swPt_sacf, + swPt_sav0, + swE_thvad, + swM_thvad, + swAdaptCount, + swBurstCount, + swHangCount, + swOldLagCount, + swVeryOldLagCount, + swOldLag; + +static Longword + pL_sacf[27], + pL_sav0[36], + L_lastdm; + +/**************************************************************************** + * + * FUNCTION: vad_reset + * + * VERSION: 1.2 + * + * PURPOSE: Resets VAD static variables to their initial value. + * + ***************************************************************************/ + +void vad_reset(void) + +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + int i; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + pswRvad[0] = 24576; + swNormRvad = 7; + swPt_sacf = 0; + swPt_sav0 = 0; + L_lastdm = 0; + swE_thvad = 21; + swM_thvad = 21875; + swAdaptCount = 0; + swBurstCount = 0; + swHangCount = -1; + swOldLagCount = 0; + swVeryOldLagCount = 0; + swOldLag = 21; + + for (i = 1; i < 9; i++) + pswRvad[i] = 0; + for (i = 0; i < 27; i++) + pL_sacf[i] = 0; + for (i = 0; i < 36; i++) + pL_sav0[i] = 0; + +} + +/**************************************************************************** + * + * FUNCTION: vad_algorithm + * + * VERSION: 1.2 + * + * PURPOSE: Returns a decision as to whether the current frame being + * processed by the speech encoder contains speech or not. + * + * INPUTS: pL_acf[0..8] autocorrelation of input signal frame + * swScaleAcf L_acf scaling factor + * pswRc[0..3] speech encoder reflection coefficients + * swPtch flag to indicate a periodic signal component + * + * OUTPUTS: pswVadFlag vad decision + * + ***************************************************************************/ + +void vad_algorithm(Longword pL_acf[9], + Shortword swScaleAcf, + Shortword pswRc[4], + Shortword swPtch, + Shortword *pswVadFlag) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + pL_av0[9], + pL_av1[9]; + + Shortword + swM_acf0, + swE_acf0, + pswRav1[9], + swNormRav1, + swM_pvad, + swE_pvad, + swStat, + swTone, + swVvad; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + energy_computation + ( + pL_acf, swScaleAcf, + pswRvad, swNormRvad, + &swM_pvad, &swE_pvad, + &swM_acf0, &swE_acf0 + ); + + average_acf + ( + pL_acf, swScaleAcf, + pL_av0, pL_av1 + ); + + predictor_values + ( + pL_av1, + pswRav1, + &swNormRav1 + ); + + spectral_comparison + ( + pswRav1, swNormRav1, + pL_av0, + &swStat + ); + + tone_detection + ( + pswRc, + &swTone + ); + + threshold_adaptation + ( + swStat, swPtch, swTone, + pswRav1, swNormRav1, + swM_pvad, swE_pvad, + swM_acf0, swE_acf0, + pswRvad, &swNormRvad, + &swM_thvad, &swE_thvad + ); + + vad_decision + ( + swM_pvad, swE_pvad, + swM_thvad, swE_thvad, + &swVvad + ); + + vad_hangover + ( + swVvad, + pswVadFlag + ); + +} + +/**************************************************************************** + * + * FUNCTION: energy_computation + * + * VERSION: 1.2 + * + * PURPOSE: Computes the input and residual energies of the adaptive + * filter in a floating point representation. + * + * INPUTS: pL_acf[0..8] autocorrelation of input signal frame + * swScaleAcf L_acf scaling factor + * pswRvad[0..8] autocorrelated adaptive filter coefficients + * swNormRvad rvad scaling factor + * + * OUTPUTS: pswM_pvad mantissa of filtered signal energy + * pswE_pvad exponent of filtered signal energy + * pswM_acf0 mantissa of signal frame energy + * pswE_acf0 exponent of signal frame energy + * + ***************************************************************************/ + +void energy_computation(Longword pL_acf[], + Shortword swScaleAcf, + Shortword pswRvad[], + Shortword swNormRvad, + Shortword *pswM_pvad, + Shortword *pswE_pvad, + Shortword *pswM_acf0, + Shortword *pswE_acf0) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + L_temp; + + Shortword + pswSacf[9], + swNormAcf, + swNormProd, + swShift; + + int + i; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** Test if acf[0] is zero ***/ + + if (pL_acf[0] == 0) + { + *pswE_pvad = -0x8000; + *pswM_pvad = 0; + *pswE_acf0 = -0x8000; + *pswM_acf0 = 0; + return; + } + + + /*** Re-normalisation of L_acf[0..8] ***/ + + swNormAcf = norm_l(pL_acf[0]); + swShift = sub(swNormAcf, 3); + + for (i = 0; i <= 8; i++) + pswSacf[i] = extract_h(L_shl(pL_acf[i], swShift)); + + + /*** Computation of e_acf0 and m_acf0 ***/ + + *pswE_acf0 = add(32, shl(swScaleAcf, 1)); + *pswE_acf0 = sub(*pswE_acf0, swNormAcf); + *pswM_acf0 = shl(pswSacf[0], 3); + + + /*** Computation of e_pvad and m_pvad ***/ + + *pswE_pvad = add(*pswE_acf0, 14); + *pswE_pvad = sub(*pswE_pvad, swNormRvad); + + L_temp = 0; + + for (i = 1; i <= 8; i++) + L_temp = L_mac(L_temp, pswSacf[i], pswRvad[i]); + + L_temp = L_add(L_temp, L_shr(L_mult(pswSacf[0], pswRvad[0]), 1)); + + if (L_temp <= 0) + L_temp = 1; + + swNormProd = norm_l(L_temp); + *pswE_pvad = sub(*pswE_pvad, swNormProd); + *pswM_pvad = extract_h(L_shl(L_temp, swNormProd)); + +} + +/**************************************************************************** + * + * FUNCTION: average_acf + * + * VERSION: 1.2 + * + * PURPOSE: Computes the arrays L_av0 [0..8] and L_av1 [0..8]. + * + * INPUTS: pL_acf[0..8] autocorrelation of input signal frame + * swScaleAcf L_acf scaling factor + * + * OUTPUTS: pL_av0[0..8] ACF averaged over last four frames + * pL_av1[0..8] ACF averaged over previous four frames + * + ***************************************************************************/ + +void average_acf(Longword pL_acf[], + Shortword swScaleAcf, + Longword pL_av0[], + Longword pL_av1[]) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword L_temp; + + Shortword swScale; + + int i; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** computation of the scaleing factor ***/ + + swScale = sub(10, shl(swScaleAcf, 1)); + + + /*** Computation of the arrays L_av0 and L_av1 ***/ + + for (i = 0; i <= 8; i++) + { + L_temp = L_shr(pL_acf[i], swScale); + pL_av0[i] = L_add(pL_sacf[i], L_temp); + pL_av0[i] = L_add(pL_sacf[i + 9], pL_av0[i]); + pL_av0[i] = L_add(pL_sacf[i + 18], pL_av0[i]); + pL_sacf[swPt_sacf + i] = L_temp; + pL_av1[i] = pL_sav0[swPt_sav0 + i]; + pL_sav0[swPt_sav0 + i] = pL_av0[i]; + } + + + /*** Update the array pointers ***/ + + if (swPt_sacf == 18) + swPt_sacf = 0; + else + swPt_sacf = add(swPt_sacf, 9); + + if (swPt_sav0 == 27) + swPt_sav0 = 0; + else + swPt_sav0 = add(swPt_sav0, 9); + +} + +/**************************************************************************** + * + * FUNCTION: predictor_values + * + * VERSION: 1.2 + * + * PURPOSE: Computes the array rav [0..8] needed for the spectral + * comparison and the threshold adaptation. + * + * INPUTS: pL_av1 [0..8] ACF averaged over previous four frames + * + * OUTPUTS: pswRav1 [0..8] ACF obtained from L_av1 + * pswNormRav1 r_av1 scaling factor + * + ***************************************************************************/ + +void predictor_values(Longword pL_av1[], + Shortword pswRav1[], + Shortword *pswNormRav1) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword + pswVpar[8], + pswAav1[9]; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + schur_recursion(pL_av1, pswVpar); + step_up(8, pswVpar, pswAav1); + compute_rav1(pswAav1, pswRav1, pswNormRav1); + +} + +/**************************************************************************** + * + * FUNCTION: schur_recursion + * + * VERSION: 1.2 + * + * PURPOSE: Uses the Schur recursion to compute adaptive filter + * reflection coefficients from an autorrelation function. + * + * INPUTS: pL_av1[0..8] autocorrelation function + * + * OUTPUTS: pswVpar[0..7] reflection coefficients + * + ***************************************************************************/ + +void schur_recursion(Longword pL_av1[], + Shortword pswVpar[]) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword + pswAcf[9], + pswPp[9], + pswKk[9], + swTemp; + + int i, + k, + m, + n; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** Schur recursion with 16-bit arithmetic ***/ + + if (pL_av1[0] == 0) + { + for (i = 0; i < 8; i++) + pswVpar[i] = 0; + return; + } + + swTemp = norm_l(pL_av1[0]); + + for (k = 0; k <= 8; k++) + pswAcf[k] = extract_h(L_shl(pL_av1[k], swTemp)); + + + /*** Initialise array pp[..] and kk[..] for the recursion: ***/ + + for (i = 1; i <= 7; i++) + pswKk[9 - i] = pswAcf[i]; + + for (i = 0; i <= 8; i++) + pswPp[i] = pswAcf[i]; + + + /*** Compute Parcor coefficients: ***/ + + for (n = 0; n < 8; n++) + { + if (pswPp[0] < abs_s(pswPp[1])) + { + for (i = n; i < 8; i++) + pswVpar[i] = 0; + return; + } + pswVpar[n] = divide_s(abs_s(pswPp[1]), pswPp[0]); + + if (pswPp[1] > 0) + pswVpar[n] = negate(pswVpar[n]); + if (n == 7) + return; + + + /*** Schur recursion: ***/ + + pswPp[0] = add(pswPp[0], mult_r(pswPp[1], pswVpar[n])); + + for (m = 1; m <= (7 - n); m++) + { + pswPp[m] = add(pswPp[1 + m], mult_r(pswKk[9 - m], pswVpar[n])); + pswKk[9 - m] = add(pswKk[9 - m], mult_r(pswPp[1 + m], pswVpar[n])); + } + } + +} + +/**************************************************************************** + * + * FUNCTION: step_up + * + * VERSION: 1.2 + * + * PURPOSE: Computes the transversal filter coefficients from the + * reflection coefficients. + * + * INPUTS: swNp filter order (2..8) + * pswVpar[0..np-1] reflection coefficients + * + * OUTPUTS: pswAav1[0..np] transversal filter coefficients + * + ***************************************************************************/ + +void step_up(Shortword swNp, + Shortword pswVpar[], + Shortword pswAav1[]) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + pL_coef[9], + pL_work[9]; + + Shortword + swTemp; + + int + i, + m; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** Initialisation of the step-up recursion ***/ + + pL_coef[0] = L_shl(0x4000L, 15); + pL_coef[1] = L_shl(L_deposit_l(pswVpar[0]), 14); + + + /*** Loop on the LPC analysis order: ***/ + + for (m = 2; m <= swNp; m++) + { + for (i = 1; i < m; i++) + { + swTemp = extract_h(pL_coef[m - i]); + pL_work[i] = L_mac(pL_coef[i], pswVpar[m - 1], swTemp); + } + for (i = 1; i < m; i++) + pL_coef[i] = pL_work[i]; + pL_coef[m] = L_shl(L_deposit_l(pswVpar[m - 1]), 14); + } + + + /*** Keep the aav1[0..swNp] in 15 bits for the following subclause ***/ + + for (i = 0; i <= swNp; i++) + pswAav1[i] = extract_h(L_shr(pL_coef[i], 3)); + +} + +/**************************************************************************** + * + * FUNCTION: compute_rav1 + * + * VERSION: 1.2 + * + * PURPOSE: Computes the autocorrelation function of the adaptive + * filter coefficients. + * + * INPUTS: pswAav1[0..8] adaptive filter coefficients + * + * OUTPUTS: pswRav1[0..8] ACF of aav1 + * pswNormRav1 r_av1 scaling factor + * + ***************************************************************************/ + +void compute_rav1(Shortword pswAav1[], + Shortword pswRav1[], + Shortword *pswNormRav1) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + pL_work[9]; + + int + i, + k; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** Computation of the rav1[0..8] ***/ + + for (i = 0; i <= 8; i++) + { + pL_work[i] = 0; + + for (k = 0; k <= 8 - i; k++) + pL_work[i] = L_mac(pL_work[i], pswAav1[k], pswAav1[k + i]); + } + + if (pL_work[0] == 0) + *pswNormRav1 = 0; + else + *pswNormRav1 = norm_l(pL_work[0]); + + for (i = 0; i <= 8; i++) + pswRav1[i] = extract_h(L_shl(pL_work[i], *pswNormRav1)); + +} + +/**************************************************************************** + * + * FUNCTION: spectral_comparison + * + * VERSION: 1.2 + * + * PURPOSE: Computes the stat flag needed for the threshold + * adaptation decision. + * + * INPUTS: pswRav1[0..8] ACF obtained from L_av1 + * swNormRav1 rav1 scaling factor + * pL_av0[0..8] ACF averaged over last four frames + * + * OUTPUTS: pswStat flag to indicate spectral stationarity + * + ***************************************************************************/ + +void spectral_comparison(Shortword pswRav1[], + Shortword swNormRav1, + Longword pL_av0[], + Shortword *pswStat) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + L_dm, + L_sump, + L_temp; + + Shortword + pswSav0[9], + swShift, + swDivShift, + swTemp; + + int + i; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** Re-normalise L_av0[0..8] ***/ + + if (pL_av0[0] == 0) + { + for (i = 0; i <= 8; i++) + pswSav0[i] = 4095; + } + else + { + swShift = sub(norm_l(pL_av0[0]), 3); + for (i = 0; i <= 8; i++) + pswSav0[i] = extract_h(L_shl(pL_av0[i], swShift)); + } + + /*** compute partial sum of dm ***/ + + L_sump = 0; + + for (i = 1; i <= 8; i++) + L_sump = L_mac(L_sump, pswRav1[i], pswSav0[i]); + + /*** compute the division of the partial sum by sav0[0] ***/ + + if (L_sump < 0) + L_temp = L_negate(L_sump); + else + L_temp = L_sump; + + if (L_temp == 0) + { + L_dm = 0; + swShift = 0; + } + else + { + pswSav0[0] = shl(pswSav0[0], 3); + swShift = norm_l(L_temp); + swTemp = extract_h(L_shl(L_temp, swShift)); + + if (pswSav0[0] >= swTemp) + { + swDivShift = 0; + swTemp = divide_s(swTemp, pswSav0[0]); + } + else + { + swDivShift = 1; + swTemp = sub(swTemp, pswSav0[0]); + swTemp = divide_s(swTemp, pswSav0[0]); + } + + if (swDivShift == 1) + L_dm = 0x8000L; + else + L_dm = 0; + + L_dm = L_shl((L_add(L_dm, L_deposit_l(swTemp))), 1); + + if (L_sump < 0) + L_dm = L_sub(0L, L_dm); + } + + + /*** Re-normalisation and final computation of L_dm ***/ + + L_dm = L_shl(L_dm, 14); + L_dm = L_shr(L_dm, swShift); + L_dm = L_add(L_dm, L_shl(L_deposit_l(pswRav1[0]), 11)); + L_dm = L_shr(L_dm, swNormRav1); + + + /*** Compute the difference and save L_dm ***/ + + L_temp = L_sub(L_dm, L_lastdm); + L_lastdm = L_dm; + + if (L_temp < 0L) + L_temp = L_negate(L_temp); + + + /*** Evaluation of the state flag ***/ + + L_temp = L_sub(L_temp, 4456L); + + if (L_temp < 0) + *pswStat = 1; + else + *pswStat = 0; + +} + +/**************************************************************************** + * + * FUNCTION: tone_detection + * + * VERSION: 1.2 + * + * PURPOSE: Computes the tone flag needed for the threshold + * adaptation decision. + * + * INPUTS: pswRc[0..3] reflection coefficients calculated in the + * speech encoder short term predictor + * + * OUTPUTS: pswTone flag to indicate a periodic signal component + * + ***************************************************************************/ + +void tone_detection(Shortword pswRc[4], + Shortword *pswTone) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + L_num, + L_den, + L_temp; + + Shortword + swTemp, + swPredErr, + pswA[3]; + + int + i; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + *pswTone = 0; + + + /*** Calculate filter coefficients ***/ + + step_up(2, pswRc, pswA); + + + /*** Calculate ( a[1] * a[1] ) ***/ + + swTemp = shl(pswA[1], 3); + L_den = L_mult(swTemp, swTemp); + + + /*** Calculate ( 4*a[2] - a[1]*a[1] ) ***/ + + L_temp = L_shl(L_deposit_h(pswA[2]), 3); + L_num = L_sub(L_temp, L_den); + + + /*** Check if pole frequency is less than 385 Hz ***/ + + if (L_num <= 0) + return; + + if (pswA[1] < 0) + { + swTemp = extract_h(L_den); + L_temp = L_msu(L_num, swTemp, 3189); + + if (L_temp < 0) + return; + } + + + /*** Calculate normalised prediction error ***/ + + swPredErr = 0x7fff; + + for (i = 0; i < 4; i++) + { + swTemp = mult(pswRc[i], pswRc[i]); + swTemp = sub(32767, swTemp); + swPredErr = mult(swPredErr, swTemp); + } + + + /*** Test if prediction error is smaller than threshold ***/ + + swTemp = sub(swPredErr, 1464); + + if (swTemp < 0) + *pswTone = 1; + +} + +/**************************************************************************** + * + * FUNCTION: threshold_adaptation + * + * VERSION: 1.2 + * + * PURPOSE: Evaluates the secondary VAD decision. If speech is not + * present then the noise model rvad and adaptive threshold + * thvad are updated. + * + * INPUTS: swStat flag to indicate spectral stationarity + * swPtch flag to indicate a periodic signal component + * swTone flag to indicate a tone signal component + * pswRav1[0..8] ACF obtained from l_av1 + * swNormRav1 r_av1 scaling factor + * swM_pvad mantissa of filtered signal energy + * swE_pvad exponent of filtered signal energy + * swM_acf0 mantissa of signal frame energy + * swE_acf0 exponent of signal frame energy + * + * OUTPUTS: pswRvad[0..8] autocorrelated adaptive filter coefficients + * pswNormRvad rvad scaling factor + * pswM_thvad mantissa of decision threshold + * pswE_thvad exponent of decision threshold + * + ***************************************************************************/ + +void threshold_adaptation(Shortword swStat, + Shortword swPtch, + Shortword swTone, + Shortword pswRav1[], + Shortword swNormRav1, + Shortword swM_pvad, + Shortword swE_pvad, + Shortword swM_acf0, + Shortword swE_acf0, + Shortword pswRvad[], + Shortword *pswNormRvad, + Shortword *pswM_thvad, + Shortword *pswE_thvad) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Longword + L_temp; + + Shortword + swTemp, + swComp, + swComp2, + swM_temp, + swE_temp; + + int + i; + + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + swComp = 0; + + /*** Test if acf0 < pth; if yes set thvad to plev ***/ + + if (swE_acf0 < E_PTH) + swComp = 1; + if ((swE_acf0 == E_PTH) && (swM_acf0 < M_PTH)) + swComp = 1; + + if (swComp == 1) + { + *pswE_thvad = E_PLEV; + *pswM_thvad = M_PLEV; + + return; + } + + + /*** Test if an adaption is required ***/ + + if (swPtch == 1) + swComp = 1; + if (swStat == 0) + swComp = 1; + if (swTone == 1) + swComp = 1; + + if (swComp == 1) + { + swAdaptCount = 0; + return; + } + + + /*** Increment adaptcount ***/ + + swAdaptCount = add(swAdaptCount, 1); + if (swAdaptCount <= 8) + return; + + + /*** computation of thvad-(thvad/dec) ***/ + + *pswM_thvad = sub(*pswM_thvad, shr(*pswM_thvad, 5)); + + if (*pswM_thvad < 0x4000) + { + *pswM_thvad = shl(*pswM_thvad, 1); + *pswE_thvad = sub(*pswE_thvad, 1); + } + + + /*** computation of pvad*fac ***/ + + L_temp = L_mult(swM_pvad, 20889); + L_temp = L_shr(L_temp, 15); + swE_temp = add(swE_pvad, 1); + + if (L_temp > 0x7fffL) + { + L_temp = L_shr(L_temp, 1); + swE_temp = add(swE_temp, 1); + } + swM_temp = extract_l(L_temp); + + + /*** test if thvad < pavd*fac ***/ + + if (*pswE_thvad < swE_temp) + swComp = 1; + + if ((*pswE_thvad == swE_temp) && (*pswM_thvad < swM_temp)) + swComp = 1; + + + /*** compute minimum(thvad+(thvad/inc), pvad*fac) when comp = 1 ***/ + + if (swComp == 1) + { + + /*** compute thvad + (thvad/inc) ***/ + + L_temp = L_add(L_deposit_l(*pswM_thvad),L_deposit_l(shr(*pswM_thvad, 4))); + + if (L_temp > 0x7fffL) + { + *pswM_thvad = extract_l(L_shr(L_temp, 1)); + *pswE_thvad = add(*pswE_thvad, 1); + } + else + *pswM_thvad = extract_l(L_temp); + + swComp2 = 0; + + if (swE_temp < *pswE_thvad) + swComp2 = 1; + + if ((swE_temp == *pswE_thvad) && (swM_temp < *pswM_thvad)) + swComp2 = 1; + + if (swComp2 == 1) + { + *pswE_thvad = swE_temp; + *pswM_thvad = swM_temp; + } + } + + + /*** compute pvad + margin ***/ + + if (swE_pvad == E_MARGIN) + { + L_temp = L_add(L_deposit_l(swM_pvad), L_deposit_l(M_MARGIN)); + swM_temp = extract_l(L_shr(L_temp, 1)); + swE_temp = add(swE_pvad, 1); + } + else + { + if (swE_pvad > E_MARGIN) + { + swTemp = sub(swE_pvad, E_MARGIN); + swTemp = shr(M_MARGIN, swTemp); + L_temp = L_add(L_deposit_l(swM_pvad), L_deposit_l(swTemp)); + + if (L_temp > 0x7fffL) + { + swE_temp = add(swE_pvad, 1); + swM_temp = extract_l(L_shr(L_temp, 1)); + } + else + { + swE_temp = swE_pvad; + swM_temp = extract_l(L_temp); + } + } + else + { + swTemp = sub(E_MARGIN, swE_pvad); + swTemp = shr(swM_pvad, swTemp); + L_temp = L_add(L_deposit_l(M_MARGIN), L_deposit_l(swTemp)); + + if (L_temp > 0x7fffL) + { + swE_temp = add(E_MARGIN, 1); + swM_temp = extract_l(L_shr(L_temp, 1)); + } + else + { + swE_temp = E_MARGIN; + swM_temp = extract_l(L_temp); + } + } + } + + /*** Test if thvad > pvad + margin ***/ + + swComp = 0; + + if (*pswE_thvad > swE_temp) + swComp = 1; + + if ((*pswE_thvad == swE_temp) && (*pswM_thvad > swM_temp)) + swComp = 1; + + if (swComp == 1) + { + *pswE_thvad = swE_temp; + *pswM_thvad = swM_temp; + } + + /*** Normalise and retain rvad[0..8] in memory ***/ + + *pswNormRvad = swNormRav1; + + for (i = 0; i <= 8; i++) + pswRvad[i] = pswRav1[i]; + + /*** Set adaptcount to adp + 1 ***/ + + swAdaptCount = 9; + +} + +/**************************************************************************** + * + * FUNCTION: vad_decision + * + * VERSION: 1.2 + * + * PURPOSE: Computes the VAD decision based on the comparison of the + * floating point representations of pvad and thvad. + * + * INPUTS: swM_pvad mantissa of filtered signal energy + * swE_pvad exponent of filtered signal energy + * swM_thvad mantissa of decision threshold + * swE_thvad exponent of decision threshold + * + * OUTPUTS: pswVvad vad decision before hangover is added + * + ***************************************************************************/ + +void vad_decision(Shortword swM_pvad, + Shortword swE_pvad, + Shortword swM_thvad, + Shortword swE_thvad, + Shortword *pswVvad) +{ + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + *pswVvad = 0; + + if (swE_pvad > swE_thvad) + *pswVvad = 1; + if ((swE_pvad == swE_thvad) && (swM_pvad > swM_thvad)) + *pswVvad = 1; + +} + +/**************************************************************************** + * + * FUNCTION: vad_hangover + * + * VERSION: 1.2 + * + * PURPOSE: Computes the final VAD decision for the current frame + * being processed. + * + * INPUTS: swVvad vad decision before hangover is added + * + * OUTPUTS: pswVadFlag vad decision after hangover is added + * + ***************************************************************************/ + +void vad_hangover(Shortword swVvad, + Shortword *pswVadFlag) +{ + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + if (swVvad == 1) + swBurstCount = add(swBurstCount, 1); + else + swBurstCount = 0; + + if (swBurstCount >= 3) + { + swHangCount = 5; + swBurstCount = 3; + } + + *pswVadFlag = swVvad; + + if (swHangCount >= 0) + { + *pswVadFlag = 1; + swHangCount = sub(swHangCount, 1); + } + +} + +/**************************************************************************** + * + * FUNCTION: periodicity_update + * + * VERSION: 1.2 + * + * PURPOSE: Computes the ptch flag needed for the threshold + * adaptation decision for the next frame. + * + * INPUTS: pswLags[0..3] speech encoder long term predictor lags + * + * OUTPUTS: pswPtch Boolean voiced / unvoiced decision + * + ***************************************************************************/ + +void periodicity_update(Shortword pswLags[4], + Shortword *pswPtch) +{ + +/*_________________________________________________________________________ + | | + | Automatic Variables | + |_________________________________________________________________________| +*/ + + Shortword + swMinLag, + swMaxLag, + swSmallLag, + swLagCount, + swTemp; + + int + i, + j; + +/*_________________________________________________________________________ + | | + | Executable Code | + |_________________________________________________________________________| +*/ + + /*** Run loop for No. of sub-segments in the frame ***/ + + swLagCount = 0; + + for (i = 0; i <= 3; i++) + { + /*** Search the maximum and minimum of consecutive lags ***/ + + if (swOldLag > pswLags[i]) + { + swMinLag = pswLags[i]; + swMaxLag = swOldLag; + } + else + { + swMinLag = swOldLag; + swMaxLag = pswLags[i]; + } + + + /*** Compute smallag (modulo operation not defined) ***/ + + swSmallLag = swMaxLag; + + for (j = 0; j <= 2; j++) + { + if (swSmallLag >= swMinLag) + swSmallLag = sub(swSmallLag, swMinLag); + } + + + /*** Minimum of smallag and minlag - smallag ***/ + + swTemp = sub(swMinLag, swSmallLag); + + if (swTemp < swSmallLag) + swSmallLag = swTemp; + + if (swSmallLag < 2) + swLagCount = add(swLagCount, 1); + + + /*** Save the current LTP lag ***/ + + swOldLag = pswLags[i]; + } + + + /*** Update the veryoldlagcount and oldlagcount ***/ + + swVeryOldLagCount = swOldLagCount; + swOldLagCount = swLagCount; + + + /*** Make ptch decision ready for next frame ***/ + + swTemp = add(swOldLagCount, swVeryOldLagCount); + + if (swTemp >= 7) + *pswPtch = 1; + else + *pswPtch = 0; + +}