Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "functions.h"
11 :
12 0 : Word16 pvq_dec_deidx_fx( /* out BER detected 1 , ok==0 */
13 : Word16 * y, /* o: decoded vector (non-scaled int) */
14 : const Word16 k_val, /* i: number of allocated pulses */
15 : const Word16 dim, /* i: Length of vector */
16 : const Word16 LS_ind, /* i; lS index 1 bit */
17 : const UWord32 UL_MPVQ_ind /* i; MPVQ index */
18 : )
19 : {
20 : Dyn_Mem_Deluxe_In(
21 : Word16 BER_flag;
22 : UWord32 h_mem[1 + KMAX_FX + 1];
23 : PvqEntry_fx entry;
24 : );
25 :
26 0 : BER_flag = 0; move16();
27 :
28 : /* get_size will likely be called before this function, as the range decoder needs the size to fetch the index
29 : */
30 0 : entry = get_size_mpvq_calc_offset_fx(dim, k_val, h_mem); /* TBD should be made into tables for N=16,10,6 */
31 :
32 0 : entry.lead_sign_ind = LS_ind; move16();
33 0 : entry.index = L_deposit_l(0); /* only in case dim == 1 */
34 0 : IF (sub(dim, 1) != 0)
35 : {
36 0 : entry.index = UL_MPVQ_ind;
37 :
38 : /* safety check in case of bit errors */
39 0 : IF (L_sub(entry.index, entry.size) >= 0)
40 : {
41 0 : BER_flag = 1; move16();
42 0 : entry.index = 0; move16(); /* return something deterministic/valid, and LOW complex */
43 : }
44 : }
45 0 : mpvq_deindex_fx(&entry, h_mem, y); /* actual deindexing */
46 :
47 : Dyn_Mem_Deluxe_Out();
48 0 : return BER_flag;
49 : }
50 :
51 :
52 :
53 : #ifdef ENABLE_HR_MODE
54 0 : void pvq_dec_scale_vec_fx(const Word32 *inQ29, Word16 adjGainQ13, Word32 *outQ)
55 : #else
56 : void pvq_dec_scale_vec_fx(const Word16 *inQ14, Word16 adjGainQ13, Word16 *outQ14)
57 : #endif
58 : {
59 : Dyn_Mem_Deluxe_In(
60 : Counter i;
61 : );
62 0 : FOR (i = 0; i < M; i++)
63 : {
64 : #ifdef ENABLE_HR_MODE
65 0 : outQ[i] = L_shr(L_add(outQ[i], Mpy_32_16_lc3plus(inQ29[i], adjGainQ13)), 1);
66 0 : move16();
67 : #else
68 : outQ14[i] = add(outQ14[i], mult_r(adjGainQ13, inQ14[i])); move16();
69 : #endif
70 : }
71 : Dyn_Mem_Deluxe_Out();
72 0 : }
73 :
74 :
75 0 : void pvq_dec_en1_normQ14_fx(/* Have to be used EXACTLY the same way in both both encoder and decoder */
76 : #ifdef ENABLE_HR_MODE
77 : Word32 * xq, /* o: en1 normalized decoded vector (Q14) */
78 : #else
79 : Word16 * xq, /* o: en1 normalized decoded vector (Q14) */
80 : #endif
81 : const Word16 *y, /* i: decoded vector (non-scaled int) */
82 : const Word16 k_val_max,
83 : /* i: max possible K in Q0 kO or kA */ /* OPT: not BE , use dynamic max pulse
84 : amplitude */
85 : const Word16 dim /* i: Length of vector */
86 : )
87 : {
88 : #ifdef ENABLE_HR_MODE
89 : Dyn_Mem_Deluxe_In(
90 : Counter i;
91 : Word32 L_tmp;
92 : Word16 shift_num, shift_tot;
93 : Word32 isqrtQ31_local;
94 : Word16 tmp, exp, exp_shift;
95 : Word32 L_yy;
96 : );
97 : #else
98 : Dyn_Mem_Deluxe_In(
99 : Counter i;
100 : Word32 L_tmp;
101 : Word16 shift_num, shift_tot;
102 : Word16 isqrtQ16_local, tmp, exp, exp_shift;
103 : Word32 L_yy;
104 : );
105 : #endif
106 :
107 : /* energy normalization starts here */
108 0 : L_yy = L_mult0(y[0], y[0]);
109 0 : FOR (i = 1; i < dim; i++)
110 : {
111 0 : L_yy = L_mac0(L_yy, y[i], y[i]); /* stay in Q0 */ /* OPT: reuse some energies from PVQ linear search */
112 : }
113 : /* 16 bit */
114 0 : IF (L_sub(L_yy, SQRT_EN_MAX_FX) < 0)
115 : {
116 0 : ASSERT(L_yy > 4); /* Q16 isqrt table lookup not valid below 5 */
117 : #ifdef ENABLE_HR_MODE
118 0 : isqrtQ31_local = isqrt_Q31tab[L_yy]; move16(); /* 1 cycle */
119 : #else
120 : isqrtQ16_local = isqrt_Q16tab[L_yy]; move16(); /* 1 cycle */
121 : #endif
122 : }
123 : ELSE
124 : {
125 : /* about 8-9 cycles */
126 0 : exp = 15; move16(); /* set ISqrt16() exp_in to get delta exp out near 0 when Lyy is in Q0 */
127 0 : tmp = ISqrt16(extract_l(L_yy),
128 : &exp); /* exp out is now a delta shift with a later tmp Q15 multiplication in mind */
129 : #ifdef ENABLE_HR_MODE
130 0 : exp_shift = add(exp, 16); /* up to Q16 */
131 0 : isqrtQ31_local = L_shl(L_deposit_l(tmp), exp_shift); /* new mantissa in a fixed Q16 */
132 : #else
133 : exp_shift = add(exp, 16 - 15); /* up to Q16 */
134 : isqrtQ16_local = shl(tmp, exp_shift); /* new mantissa in a fixed Q16 */
135 : #endif
136 : }
137 :
138 0 : shift_num = norm_s(k_val_max); /* simply account for the preknown fixed max possible pulseamp in y */
139 0 : shift_tot = sub(14 - 1, shift_num); /* upshift to get to Q14 */
140 0 : FOR (i = 0; i < dim; i++) /* upshifted y[i] used */
141 : {
142 : #ifdef ENABLE_HR_MODE
143 0 : L_tmp = Mpy_32_16_lc3plus(isqrtQ31_local, shl_pos(y[i], shift_num)); /* Q(16+0+shift_num +1 = shift_num+1 */
144 0 : xq[i] = L_shl(L_tmp, shift_tot + 1); move32(); /* Q30 , */
145 : #else
146 : L_tmp = L_mult(isqrtQ16_local, shl_pos(y[i], shift_num)); /* Q(16+0+shift_num +1 = shift_num+1 */
147 : xq[i] = round_fx(L_shl(L_tmp, shift_tot)); move16(); /* Q14 , */
148 : #endif
149 : }
150 :
151 : Dyn_Mem_Deluxe_Out();
152 0 : }
153 :
|