1use crate::silk::define::*;
2use crate::silk::gain_quant::*;
3use crate::silk::lpc_analysis::*;
4use crate::silk::ltp_analysis::*;
5use crate::silk::macros::*;
6use crate::silk::nlsf::*;
7use crate::silk::sigm::*;
8use crate::silk::sigproc_fix::*;
9use crate::silk::structs::*;
10use crate::silk::tables::*;
11
12#[inline(always)]
13pub fn silk_find_pred_coefs_fix(
14 ps_enc: &mut SilkEncoderState,
15 ps_enc_ctrl: &mut SilkEncoderControl,
16 res_pitch: &[i16],
17 res_pitch_frame_idx: usize,
18 x: &[i16],
19 x_buf_full: &[i16],
20 cond_coding: i32,
21) {
22 let _prof = crate::prof::scope(crate::prof::Stage::SilkPred);
23 let mut inv_gains_q16 = [0i32; MAX_NB_SUBFR];
24 let mut local_gains = [0i32; MAX_NB_SUBFR];
25 let mut nlsf_q15 = [0i16; MAX_LPC_ORDER];
26 let mut min_gain_q16: i32;
27 let mut min_inv_gain_q30: i32;
28
29 min_gain_q16 = i32::MAX >> 6;
30 for i in 0..ps_enc.s_cmn.nb_subfr as usize {
31 min_gain_q16 = min_gain_q16.min(ps_enc_ctrl.gains_q16[i]);
32 }
33 for i in 0..ps_enc.s_cmn.nb_subfr as usize {
34 inv_gains_q16[i] = silk_div32_varq(min_gain_q16, ps_enc_ctrl.gains_q16[i], 16 - 2);
35
36 inv_gains_q16[i] = inv_gains_q16[i].max(100);
37
38 local_gains[i] = silk_div32(1 << 16, inv_gains_q16[i]);
39 }
40
41 let mut lpc_in_pre = [0i16; MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH];
42
43 if ps_enc.s_cmn.indices.signal_type == TYPE_VOICED as i8 {
44 let mut x_xltp_q17 = [0i32; MAX_NB_SUBFR * LTP_ORDER];
45 let mut xxltp_q17 = [0i32; MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER];
46
47 silk_find_ltp_fix(
48 &mut xxltp_q17,
49 &mut x_xltp_q17,
50 res_pitch,
51 res_pitch_frame_idx,
52 &ps_enc_ctrl.pitch_l,
53 ps_enc.s_cmn.subfr_length as usize,
54 ps_enc.s_cmn.nb_subfr as usize,
55 0,
56 );
57
58 silk_quant_ltp_gains(
59 &mut ps_enc_ctrl.ltp_coef_q14,
60 &mut ps_enc.s_cmn.indices.ltp_index,
61 &mut ps_enc.s_cmn.indices.per_index,
62 &mut ps_enc.s_cmn.sum_log_gain_q7,
63 &mut ps_enc_ctrl.ltp_red_cod_gain_q7,
64 &xxltp_q17,
65 &x_xltp_q17,
66 ps_enc.s_cmn.subfr_length,
67 ps_enc.s_cmn.nb_subfr as usize,
68 0,
69 );
70
71 silk_ltp_scale_ctrl_fix(ps_enc, ps_enc_ctrl, cond_coding);
72
73 let predict_lpc_order = ps_enc.s_cmn.predict_lpc_order as usize;
74 let x_base_for_ltp = ps_enc.s_cmn.ltp_mem_length as usize - predict_lpc_order;
75 silk_ltp_analysis_filter_fix(
76 &mut lpc_in_pre,
77 x_buf_full,
78 x_base_for_ltp,
79 &ps_enc_ctrl.ltp_coef_q14,
80 &ps_enc_ctrl.pitch_l,
81 &inv_gains_q16,
82 ps_enc.s_cmn.subfr_length as usize,
83 ps_enc.s_cmn.nb_subfr as usize,
84 ps_enc.s_cmn.predict_lpc_order as usize,
85 );
86 } else {
87 let mut x_ptr_idx = 0;
88 let mut x_pre_ptr_idx = 0;
89 for i in 0..ps_enc.s_cmn.nb_subfr as usize {
90 silk_scale_copy_vector16(
91 &mut lpc_in_pre[x_pre_ptr_idx..],
92 &x[x_ptr_idx..],
93 inv_gains_q16[i],
94 (ps_enc.s_cmn.subfr_length + ps_enc.s_cmn.predict_lpc_order) as usize,
95 );
96 x_pre_ptr_idx += (ps_enc.s_cmn.subfr_length + ps_enc.s_cmn.predict_lpc_order) as usize;
97 x_ptr_idx += ps_enc.s_cmn.subfr_length as usize;
98 }
99
100 ps_enc_ctrl.ltp_coef_q14.fill(0);
101 ps_enc_ctrl.ltp_red_cod_gain_q7 = 0;
102 ps_enc.s_cmn.sum_log_gain_q7 = 0;
103 ps_enc_ctrl.ltp_scale_q14 = 0;
104 }
105
106 if ps_enc.s_cmn.first_frame_after_reset != 0 {
107 min_inv_gain_q30 =
108 (1.0f32 / MAX_PREDICTION_POWER_GAIN_AFTER_RESET * 1073741824.0f32) as i32;
109 } else {
110 min_inv_gain_q30 = silk_log2lin(silk_smlawb(
111 16 << 7,
112 ps_enc_ctrl.ltp_red_cod_gain_q7,
113 (1.0f32 / 3.0f32 * 65536.0f32) as i32,
114 ));
115 min_inv_gain_q30 = silk_div32_varq(
116 min_inv_gain_q30,
117 silk_smulww(
118 MAX_PREDICTION_POWER_GAIN as i32,
119 silk_smlawb(
120 (0.25f32 * 262144.0f32) as i32,
121 (0.75f32 * 262144.0f32) as i32,
122 ps_enc_ctrl.coding_quality_q14,
123 ),
124 ),
125 14,
126 );
127 }
128
129 silk_find_lpc_fix(
130 &mut ps_enc.s_cmn,
131 &mut nlsf_q15,
132 &lpc_in_pre,
133 min_inv_gain_q30,
134 );
135
136 silk_process_nlsfs(ps_enc, ps_enc_ctrl, &mut nlsf_q15);
137
138 silk_residual_energy_fix(
139 &mut ps_enc_ctrl.res_nrg,
140 &mut ps_enc_ctrl.res_nrg_q,
141 &lpc_in_pre,
142 &ps_enc_ctrl.pred_coef_q12,
143 &local_gains,
144 ps_enc.s_cmn.subfr_length,
145 ps_enc.s_cmn.nb_subfr,
146 ps_enc.s_cmn.predict_lpc_order,
147 );
148}
149
150pub fn silk_process_gains_fix(
151 ps_enc: &mut SilkEncoderState,
152 ps_enc_ctrl: &mut SilkEncoderControl,
153 cond_coding: i32,
154) {
155 let ps_shape_st = &mut ps_enc.s_shape;
156 let s_q15: i32;
157 let mut gain_q16: i32;
158 let mut gain_squared_q16: i32;
159 let mut res_nrg_part: i32;
160
161 if ps_enc.s_cmn.indices.signal_type == TYPE_VOICED as i8 {
162 s_q15 = -silk_sigm_q15(silk_rshift_round(
163 ps_enc_ctrl.ltp_red_cod_gain_q7 - (12.0 * 128.0) as i32,
164 4,
165 ));
166 for k in 0..ps_enc.s_cmn.nb_subfr as usize {
167 ps_enc_ctrl.gains_q16[k] =
168 silk_smlawb(ps_enc_ctrl.gains_q16[k], ps_enc_ctrl.gains_q16[k], s_q15);
169 }
170 }
171
172 let log2lin_arg = silk_smulwb(
173 ((21.0 + 16.0 / 0.33) * 128.0) as i32 - ps_enc.s_cmn.snr_db_q7,
174 21627_i32,
175 );
176 let log2lin_val = silk_log2lin(log2lin_arg);
177 let inv_max_sqr_val_q16 = silk_div32_16(log2lin_val, ps_enc.s_cmn.subfr_length);
178
179 for k in 0..ps_enc.s_cmn.nb_subfr as usize {
180 let res_nrg = ps_enc_ctrl.res_nrg[k];
181 res_nrg_part = silk_smulww(res_nrg, inv_max_sqr_val_q16);
182 if ps_enc_ctrl.res_nrg_q[k] > 0 {
183 res_nrg_part = silk_rshift_round(res_nrg_part, ps_enc_ctrl.res_nrg_q[k]);
184 } else {
185 let neg_q = (-ps_enc_ctrl.res_nrg_q[k]).min(30);
186 if neg_q == 0 || res_nrg_part >= (i32::MAX >> neg_q) {
187 res_nrg_part = if neg_q == 0 { res_nrg_part } else { i32::MAX };
188 } else {
189 res_nrg_part <<= neg_q;
190 }
191 }
192 gain_q16 = ps_enc_ctrl.gains_q16[k];
193 gain_squared_q16 = silk_add_sat32(res_nrg_part, silk_smmul(gain_q16, gain_q16));
194 if gain_squared_q16 < i16::MAX as i32 {
195 gain_squared_q16 = silk_smlaww(res_nrg_part << 16, gain_q16, gain_q16);
196
197 gain_q16 = silk_sqrt_approx(gain_squared_q16);
198 gain_q16 = silk_min_32(gain_q16, i32::MAX >> 8);
199 ps_enc_ctrl.gains_q16[k] = silk_lshift_sat32(gain_q16, 8);
200 } else {
201 gain_q16 = silk_sqrt_approx(gain_squared_q16);
202 gain_q16 = silk_min_32(gain_q16, i32::MAX >> 16);
203 ps_enc_ctrl.gains_q16[k] = silk_lshift_sat32(gain_q16, 16);
204 }
205 }
206
207 for k in 0..ps_enc.s_cmn.nb_subfr as usize {
208 ps_enc_ctrl.gains_unq_q16[k] = ps_enc_ctrl.gains_q16[k];
209 }
210 ps_enc_ctrl.last_gain_index_prev = ps_shape_st.last_gain_index;
211
212 silk_gains_quant(
213 &mut ps_enc.s_cmn.indices.gains_indices,
214 &mut ps_enc_ctrl.gains_q16,
215 &mut ps_shape_st.last_gain_index,
216 if cond_coding == CODE_CONDITIONALLY {
217 1
218 } else {
219 0
220 },
221 ps_enc.s_cmn.nb_subfr as usize,
222 );
223
224 if ps_enc.s_cmn.indices.signal_type == TYPE_VOICED as i8 {
225 if ps_enc_ctrl.ltp_red_cod_gain_q7 + (ps_enc.s_cmn.input_tilt_q15 >> 8) > 128 {
226 ps_enc.s_cmn.indices.quant_offset_type = 0;
227 } else {
228 ps_enc.s_cmn.indices.quant_offset_type = 1;
229 }
230 }
231
232 let quant_offset_q10 = SILK_QUANTIZATION_OFFSETS_Q10
233 [(ps_enc.s_cmn.indices.signal_type >> 1) as usize]
234 [ps_enc.s_cmn.indices.quant_offset_type as usize] as i32;
235
236 const LAMBDA_OFFSET_Q10: i32 = 1229;
237 const LAMBDA_DELAYED_DECISIONS_Q10: i32 = -50;
238 const LAMBDA_SPEECH_ACT_Q18: i32 = -52428;
239 const LAMBDA_INPUT_QUALITY_Q12: i32 = -409;
240 const LAMBDA_CODING_QUALITY_Q12: i32 = -818;
241 const LAMBDA_QUANT_OFFSET_Q16: i32 = 52429;
242
243 ps_enc_ctrl.lambda_q10 = LAMBDA_OFFSET_Q10
244 + silk_smulbb(
245 LAMBDA_DELAYED_DECISIONS_Q10,
246 ps_enc.s_cmn.n_states_delayed_decision,
247 )
248 + silk_smulwb(LAMBDA_SPEECH_ACT_Q18, ps_enc.s_cmn.speech_activity_q8)
249 + silk_smulwb(LAMBDA_INPUT_QUALITY_Q12, ps_enc_ctrl.input_quality_q14)
250 + silk_smulwb(LAMBDA_CODING_QUALITY_Q12, ps_enc_ctrl.coding_quality_q14)
251 + silk_smulwb(LAMBDA_QUANT_OFFSET_Q16, quant_offset_q10);
252}
253
254pub fn silk_ltp_scale_ctrl_fix(
255 ps_enc: &mut SilkEncoderState,
256 ps_enc_ctrl: &mut SilkEncoderControl,
257 cond_coding: i32,
258) {
259 if cond_coding == CODE_INDEPENDENTLY {
260 let mut round_loss = ps_enc.s_cmn.packet_loss_perc * ps_enc.s_cmn.n_frames_per_packet;
261 if ps_enc.s_cmn.lbrr_flag != 0 {
262 round_loss = 2 + silk_smulbb(round_loss, round_loss) / 100;
263 }
264 ps_enc.s_cmn.indices.ltp_scale_index =
265 (silk_smulbb(ps_enc_ctrl.ltp_red_cod_gain_q7, round_loss)
266 > silk_log2lin(128 * 7 + 2900 - ps_enc.s_cmn.snr_db_q7)) as i8;
267 ps_enc.s_cmn.indices.ltp_scale_index +=
268 (silk_smulbb(ps_enc_ctrl.ltp_red_cod_gain_q7, round_loss)
269 > silk_log2lin(128 * 7 + 3900 - ps_enc.s_cmn.snr_db_q7)) as i8;
270 } else {
271 ps_enc.s_cmn.indices.ltp_scale_index = 0;
272 }
273 ps_enc_ctrl.ltp_scale_q14 =
274 SILK_LTP_SCALES_TABLE_Q14[ps_enc.s_cmn.indices.ltp_scale_index as usize] as i32;
275}