blob: f6c9caf4f432d5499046d6e12f07afeb5723e368
1 | /* |
2 | *=================================================================== |
3 | * 3GPP AMR Wideband Floating-point Speech Codec |
4 | *=================================================================== |
5 | */ |
6 | #include <stdlib.h> |
7 | #include <memory.h> |
8 | #include <math.h> |
9 | #include "typedef.h" |
10 | #include "dec_dtx.h" |
11 | #include "dec_lpc.h" |
12 | #include "dec_util.h" |
13 | |
14 | |
15 | #define MAX_31 (Word32)0x3FFFFFFF |
16 | #define L_FRAME 256 /* Frame size */ |
17 | #define RX_SPEECH_LOST 2 |
18 | #define RX_SPEECH_BAD 3 |
19 | #define RX_SID_FIRST 4 |
20 | #define RX_SID_UPDATE 5 |
21 | #define RX_SID_BAD 6 |
22 | #define RX_NO_DATA 7 |
23 | #define ISF_GAP 128 /* 50 */ |
24 | #define D_DTX_MAX_EMPTY_THRESH 50 |
25 | #define GAIN_FACTOR 75 |
26 | #define ISF_FACTOR_LOW 256 |
27 | #define ISF_FACTOR_STEP 2 |
28 | #define ISF_DITH_GAP 448 |
29 | #define D_DTX_HANG_CONST 7 /* yields eight frames of SP HANGOVER */ |
30 | #define D_DTX_ELAPSED_FRAMES_THRESH (24 + 7 - 1) |
31 | #define RANDOM_INITSEED 21845 /* own random init value */ |
32 | |
33 | |
34 | /* |
35 | * D_DTX_reset |
36 | * |
37 | * Parameters: |
38 | * st O: state struct |
39 | * |
40 | * Function: |
41 | * Initializes state memory |
42 | * |
43 | * Returns: |
44 | * non-zero with error, zero for ok |
45 | */ |
46 | int D_DTX_reset(D_DTX_State *st, const Word16 *isf_init) |
47 | { |
48 | Word32 i; |
49 | |
50 | if (st == (D_DTX_State*)NULL) { |
51 | return(-1); |
52 | } |
53 | st->mem_since_last_sid = 0; |
54 | st->mem_true_sid_period_inv = (1 << 13); /* 0.25 in Q15 */ |
55 | st->mem_log_en = 3500; |
56 | st->mem_log_en_prev = 3500; |
57 | |
58 | /* low level noise for better performance in DTX handover cases */ |
59 | st->mem_cng_seed = RANDOM_INITSEED; |
60 | st->mem_hist_ptr = 0; |
61 | |
62 | /* Init isf_hist[] and decoder log frame energy */ |
63 | memcpy(st->mem_isf, isf_init, M * sizeof(Word16)); |
64 | memcpy(st->mem_isf_prev, isf_init, M * sizeof(Word16)); |
65 | |
66 | for (i = 0; i < D_DTX_HIST_SIZE; i++) { |
67 | memcpy(&st->mem_isf_buf[i * M], isf_init, M * sizeof(Word16)); |
68 | st->mem_log_en_buf[i] = 3500; |
69 | } |
70 | st->mem_dtx_hangover_count = D_DTX_HANG_CONST; |
71 | st->mem_dec_ana_elapsed_count = 127; |
72 | st->mem_sid_frame = 0; |
73 | st->mem_valid_data = 0; |
74 | st->mem_dtx_hangover_added = 0; |
75 | st->mem_dtx_global_state = SPEECH; |
76 | st->mem_data_updated = 0; |
77 | st->mem_dither_seed = RANDOM_INITSEED; |
78 | st->mem_cn_dith = 0; |
79 | |
80 | return(0); |
81 | } |
82 | |
83 | |
84 | /* |
85 | * D_DTX_init |
86 | * |
87 | * Parameters: |
88 | * st I/O: state struct |
89 | * |
90 | * Function: |
91 | * Allocates state memory and initializes state memory |
92 | * |
93 | * Returns: |
94 | * non-zero with error, zero for ok |
95 | */ |
96 | int D_DTX_init(D_DTX_State **st, const Word16 *isf_init) |
97 | { |
98 | D_DTX_State *s; |
99 | |
100 | if (st == (D_DTX_State**)NULL) { |
101 | return(-1); |
102 | } |
103 | |
104 | *st = NULL; |
105 | |
106 | /* allocate memory */ |
107 | if ((s = (D_DTX_State*)malloc(sizeof(D_DTX_State))) == NULL) { |
108 | return(-1); |
109 | } |
110 | |
111 | D_DTX_reset(s, isf_init); |
112 | *st = s; |
113 | |
114 | return(0); |
115 | } |
116 | |
117 | |
118 | /* |
119 | * D_DTX_exit |
120 | * |
121 | * Parameters: |
122 | * state I/0: State struct |
123 | * |
124 | * Function: |
125 | * The memory used for state memory is freed |
126 | * |
127 | * Returns: |
128 | * void |
129 | */ |
130 | void D_DTX_exit(D_DTX_State **st) |
131 | { |
132 | if (st == NULL || *st == NULL) { |
133 | return; |
134 | } |
135 | |
136 | /* deallocate memory */ |
137 | free(*st); |
138 | *st = NULL; |
139 | |
140 | return; |
141 | } |
142 | |
143 | |
144 | /* |
145 | * D_DTX_rx_handler |
146 | * |
147 | * Parameters: |
148 | * st I/O: State struct |
149 | * frame_type I: Frame type |
150 | * |
151 | * Function: |
152 | * Analyze received frame |
153 | * |
154 | * Table of new SPD synthesis states |
155 | * |
156 | * | previous SPD_synthesis_state |
157 | * Incoming | |
158 | * frame_type | SPEECH | DTX | D_DTX_MUTE |
159 | * --------------------------------------------------------------- |
160 | * RX_SPEECH_GOOD , | | | |
161 | * RX_SPEECH_PR_DEGRADED | SPEECH | SPEECH | SPEECH |
162 | * ---------------------------------------------------------------- |
163 | * RX_SPEECH_BAD, | SPEECH | DTX | D_DTX_MUTE |
164 | * ---------------------------------------------------------------- |
165 | * RX_SID_FIRST, | DTX | DTX/(D_DTX_MUTE)| D_DTX_MUTE |
166 | * ---------------------------------------------------------------- |
167 | * RX_SID_UPDATE, | DTX | DTX | DTX |
168 | * ---------------------------------------------------------------- |
169 | * RX_SID_BAD, | DTX | DTX/(D_DTX_MUTE)| D_DTX_MUTE |
170 | * ---------------------------------------------------------------- |
171 | * RX_NO_DATA, | SPEECH | DTX/(D_DTX_MUTE)| D_DTX_MUTE |
172 | * RX_SPARE |(class2 garb.)| | |
173 | * ---------------------------------------------------------------- |
174 | * |
175 | * Returns: |
176 | * new state |
177 | */ |
178 | UWord8 D_DTX_rx_handler(D_DTX_State *st, UWord8 frame_type) |
179 | { |
180 | UWord8 newState; |
181 | UWord8 encState; |
182 | |
183 | /* DTX if SID frame or previously in DTX{_MUTE} |
184 | * and (NO_RX OR BAD_SPEECH) |
185 | */ |
186 | if ((frame_type == RX_SID_FIRST) | (frame_type == RX_SID_UPDATE) | |
187 | (frame_type == RX_SID_BAD) | (((st->mem_dtx_global_state == DTX) | |
188 | (st->mem_dtx_global_state == D_DTX_MUTE)) & ((frame_type == RX_NO_DATA) | |
189 | (frame_type == RX_SPEECH_BAD) | (frame_type == RX_SPEECH_LOST)))) { |
190 | newState = DTX; |
191 | |
192 | /* stay in mute for these input types */ |
193 | if ((st->mem_dtx_global_state == D_DTX_MUTE) & |
194 | ((frame_type == RX_SID_BAD) | (frame_type == RX_SID_FIRST) | |
195 | (frame_type == RX_SPEECH_LOST) | (frame_type == RX_NO_DATA))) { |
196 | newState = D_DTX_MUTE; |
197 | } |
198 | |
199 | /* evaluate if noise parameters are too old */ |
200 | /* since_last_sid is reset when CN parameters have been updated */ |
201 | st->mem_since_last_sid = D_UTIL_saturate(st->mem_since_last_sid + 1); |
202 | |
203 | /* no update of sid parameters in DTX for a Word32 while */ |
204 | if ((frame_type != RX_SID_UPDATE) && |
205 | (st->mem_since_last_sid > D_DTX_MAX_EMPTY_THRESH)) { |
206 | newState = D_DTX_MUTE; |
207 | } |
208 | } else { |
209 | newState = SPEECH; |
210 | st->mem_since_last_sid = 0; |
211 | } |
212 | |
213 | /* |
214 | * reset the decAnaElapsed Counter when receiving CNI data the first |
215 | * time, to robustify counter missmatch after handover |
216 | * this might delay the bwd CNI analysis in the new decoder slightly. |
217 | */ |
218 | if ((st->mem_data_updated == 0) & (frame_type == RX_SID_UPDATE)) { |
219 | st->mem_dec_ana_elapsed_count = 0; |
220 | } |
221 | |
222 | /* |
223 | * update the SPE-SPD DTX hangover synchronization |
224 | * to know when SPE has added dtx hangover |
225 | */ |
226 | st->mem_dec_ana_elapsed_count++; |
227 | |
228 | /* saturate */ |
229 | if (st->mem_dec_ana_elapsed_count > 127) { |
230 | st->mem_dec_ana_elapsed_count = 127; |
231 | } |
232 | |
233 | st->mem_dtx_hangover_added = 0; |
234 | |
235 | if ((frame_type == RX_SID_FIRST) | (frame_type == RX_SID_UPDATE) | |
236 | (frame_type == RX_SID_BAD) | (frame_type == RX_NO_DATA)) { |
237 | encState = DTX; |
238 | } else { |
239 | encState = SPEECH; |
240 | } |
241 | |
242 | if (encState == SPEECH) { |
243 | st->mem_dtx_hangover_count = D_DTX_HANG_CONST; |
244 | } else { |
245 | if (st->mem_dec_ana_elapsed_count > D_DTX_ELAPSED_FRAMES_THRESH) { |
246 | st->mem_dtx_hangover_added = 1; |
247 | st->mem_dec_ana_elapsed_count = 0; |
248 | st->mem_dtx_hangover_count = 0; |
249 | } else if (st->mem_dtx_hangover_count == 0) { |
250 | st->mem_dec_ana_elapsed_count = 0; |
251 | } else { |
252 | st->mem_dtx_hangover_count--; |
253 | } |
254 | } |
255 | |
256 | if (newState != SPEECH) { |
257 | /* |
258 | * DTX or D_DTX_MUTE |
259 | * CN data is not in a first SID, first SIDs are marked as SID_BAD |
260 | * but will do backwards analysis if a hangover period has been added |
261 | * according to the state machine above |
262 | */ |
263 | st->mem_sid_frame = 0; |
264 | st->mem_valid_data = 0; |
265 | |
266 | if (frame_type == RX_SID_FIRST) { |
267 | st->mem_sid_frame = 1; |
268 | } else if (frame_type == RX_SID_UPDATE) { |
269 | st->mem_sid_frame = 1; |
270 | st->mem_valid_data = 1; |
271 | } else if (frame_type == RX_SID_BAD) { |
272 | st->mem_sid_frame = 1; |
273 | st->mem_dtx_hangover_added = 0; /* use old data */ |
274 | } |
275 | } |
276 | |
277 | return newState; |
278 | |
279 | /* newState is used by both SPEECH AND DTX synthesis routines */ |
280 | } |
281 | |
282 | |
283 | /* |
284 | * D_DTX_cn_dithering |
285 | * |
286 | * Parameters: |
287 | * isf I/O: CN ISF vector |
288 | * L_log_en_int I/O: energy parameter |
289 | * dither_seed I/O: random seed |
290 | * |
291 | * Function: |
292 | * Confort noise dithering |
293 | * |
294 | * Returns: |
295 | * void |
296 | */ |
297 | static void D_DTX_cn_dithering(Word16 isf[M], Word32 *L_log_en_int, |
298 | Word16 *dither_seed) |
299 | { |
300 | Word32 temp, temp1, i, dither_fac, rand_dith, rand_dith2; |
301 | |
302 | /* Insert comfort noise dithering for energy parameter */ |
303 | rand_dith = D_UTIL_random(dither_seed) >> 1; |
304 | rand_dith2 = D_UTIL_random(dither_seed) >> 1; |
305 | rand_dith = rand_dith + rand_dith2; |
306 | *L_log_en_int = *L_log_en_int + ((rand_dith * GAIN_FACTOR) << 1); |
307 | |
308 | if (*L_log_en_int < 0) { |
309 | *L_log_en_int = 0; |
310 | } |
311 | |
312 | /* Insert comfort noise dithering for spectral parameters (ISF-vector) */ |
313 | dither_fac = ISF_FACTOR_LOW; |
314 | rand_dith = D_UTIL_random(dither_seed) >> 1; |
315 | rand_dith2 = D_UTIL_random(dither_seed) >> 1; |
316 | rand_dith = rand_dith + rand_dith2; |
317 | temp = isf[0] + (((rand_dith * dither_fac) + 0x4000) >> 15); |
318 | |
319 | /* Make sure that isf[0] will not get negative values */ |
320 | if (temp < ISF_GAP) { |
321 | isf[0] = ISF_GAP; |
322 | } else { |
323 | isf[0] = (Word16)temp; |
324 | } |
325 | |
326 | for (i = 1; i < M - 1; i++) { |
327 | dither_fac = dither_fac + ISF_FACTOR_STEP; |
328 | rand_dith = D_UTIL_random(dither_seed) >> 1; |
329 | rand_dith2 = D_UTIL_random(dither_seed) >> 1; |
330 | rand_dith = rand_dith + rand_dith2; |
331 | temp = isf[i] + (((rand_dith * dither_fac) + 0x4000) >> 15); |
332 | temp1 = temp - isf[i - 1]; |
333 | |
334 | /* Make sure that isf spacing remains at least ISF_DITH_GAP Hz */ |
335 | if (temp1 < ISF_DITH_GAP) { |
336 | isf[i] = (Word16)(isf[i - 1] + ISF_DITH_GAP); |
337 | } else { |
338 | isf[i] = (Word16)temp; |
339 | } |
340 | } |
341 | |
342 | /* Make sure that isf[M-2] will not get values above 16384 */ |
343 | if (isf[M - 2] > 16384) { |
344 | isf[M - 2] = 16384; |
345 | } |
346 | |
347 | return; |
348 | } |
349 | |
350 | |
351 | /* |
352 | * D_DTX_exe |
353 | * |
354 | * Parameters: |
355 | * st I/O: state struct |
356 | * exc2 O: CN excitation |
357 | * new_state I: New DTX state |
358 | * prms I: Vector of synthesis parameters |
359 | * isf O: CN ISF vector |
360 | * |
361 | * Function: |
362 | * Confort noise generation |
363 | * |
364 | * Returns: |
365 | * void |
366 | */ |
367 | void D_DTX_exe(D_DTX_State *st, Word16 *exc2, Word16 new_state, Word16 isf[], |
368 | Word16 **prms) |
369 | { |
370 | |
371 | Word32 i, j, L_tmp, ptr; |
372 | Word32 exp0, int_fac; |
373 | Word32 gain; |
374 | Word32 L_isf[M], L_log_en_int, level32, ener32; |
375 | Word16 log_en_index; |
376 | Word16 tmp_int_length; |
377 | Word16 exp, log_en_int_e, log_en_int_m, level; |
378 | |
379 | |
380 | /* |
381 | * This function is called if synthesis state is not SPEECH. |
382 | * The globally passed inputs to this function are |
383 | * st->sid_frame |
384 | * st->valid_data |
385 | * st->dtxHangoverAdded |
386 | * new_state (SPEECH, DTX, D_DTX_MUTE) |
387 | */ |
388 | if ((st->mem_dtx_hangover_added != 0) & (st->mem_sid_frame != 0)) { |
389 | /* sid_first after dtx hangover period |
390 | * or sid_upd after dtxhangover |
391 | * consider twice the last frame |
392 | */ |
393 | ptr = st->mem_hist_ptr + 1; |
394 | |
395 | if (ptr == D_DTX_HIST_SIZE) { |
396 | ptr = 0; |
397 | } |
398 | |
399 | memcpy(&st->mem_isf_buf[ptr * M], &st->mem_isf_buf[st->mem_hist_ptr * M], |
400 | M * sizeof(Word16)); |
401 | |
402 | st->mem_log_en_buf[ptr] = st->mem_log_en_buf[st->mem_hist_ptr]; |
403 | |
404 | /* compute mean log energy and isf from decoded signal (SID_FIRST) */ |
405 | st->mem_log_en = 0; |
406 | memset(L_isf, 0, M * sizeof(Word32)); |
407 | |
408 | /* average energy and isf */ |
409 | for (i = 0; i < D_DTX_HIST_SIZE; i++) { |
410 | /* |
411 | * Division by D_DTX_HIST_SIZE = 8 has been done in dtx_buffer log_en |
412 | * is in Q10 |
413 | */ |
414 | st->mem_log_en = (Word16)(st->mem_log_en + st->mem_log_en_buf[i]); |
415 | |
416 | for (j = 0; j < M; j++) { |
417 | L_isf[j] = L_isf[j] + st->mem_isf_buf[i * M + j]; |
418 | } |
419 | } |
420 | |
421 | /* st->log_en in Q9 */ |
422 | st->mem_log_en = (Word16)(st->mem_log_en >> 1); |
423 | |
424 | /* |
425 | * Add 2 in Q9, in order to have only positive values for Pow2 |
426 | * this value is subtracted back after Pow2 function |
427 | */ |
428 | st->mem_log_en = (Word16)(st->mem_log_en + 1024); |
429 | |
430 | if (st->mem_log_en < 0) { |
431 | st->mem_log_en = 0; |
432 | } |
433 | |
434 | for (j = 0; j < M; j++) { |
435 | st->mem_isf[j] = (Word16)(L_isf[j] >> 3); /* divide by 8 */ |
436 | } |
437 | } |
438 | |
439 | if (st->mem_sid_frame != 0) { |
440 | /* |
441 | * Set old SID parameters, always shift |
442 | * even if there is no new valid_data |
443 | */ |
444 | memcpy(st->mem_isf_prev, st->mem_isf, M * sizeof(Word16)); |
445 | st->mem_log_en_prev = st->mem_log_en; |
446 | |
447 | if (st->mem_valid_data != 0) { /* new data available (no CRC) */ |
448 | /* st->true_sid_period_inv = 1.0f/st->since_last_sid; */ |
449 | |
450 | /* |
451 | * Compute interpolation factor, since the division only works |
452 | * for values of since_last_sid < 32 we have to limit |
453 | * the interpolation to 32 frames |
454 | */ |
455 | tmp_int_length = st->mem_since_last_sid; |
456 | |
457 | if (tmp_int_length > 32) { |
458 | tmp_int_length = 32; |
459 | } |
460 | |
461 | if (tmp_int_length >= 2) { |
462 | st->mem_true_sid_period_inv = |
463 | (Word16)(0x2000000 / (tmp_int_length << 10)); |
464 | } else { |
465 | st->mem_true_sid_period_inv = 1 << 14; /* 0.5 it Q15 */ |
466 | } |
467 | |
468 | D_LPC_isf_noise_d(*prms, st->mem_isf); |
469 | (*prms) += 5; |
470 | log_en_index = *(*prms)++; |
471 | |
472 | /* read background noise stationarity information */ |
473 | st->mem_cn_dith = *(*prms)++; |
474 | |
475 | /* |
476 | * st->log_en = (Float32)log_en_index / 2.625 - 2.0; |
477 | * log2(E) in Q9 (log2(E) lies in between -2:22) |
478 | */ |
479 | st->mem_log_en = (Word16)(log_en_index << (15 - 6)); |
480 | |
481 | /* Divide by 2.625 */ |
482 | st->mem_log_en = (Word16)((st->mem_log_en * 12483) >> 15); |
483 | |
484 | /* |
485 | * Subtract 2 in Q9 is done later, after Pow2 function |
486 | * no interpolation at startup after coder reset |
487 | * or when SID_UPD has been received right after SPEECH |
488 | */ |
489 | if ((st->mem_data_updated == 0) || |
490 | (st->mem_dtx_global_state == SPEECH)) { |
491 | memcpy(st->mem_isf_prev, st->mem_isf, M * sizeof(Word16)); |
492 | st->mem_log_en_prev = st->mem_log_en; |
493 | } |
494 | } /* endif valid_data */ |
495 | } /* endif sid_frame */ |
496 | |
497 | if ((st->mem_sid_frame != 0) && (st->mem_valid_data != 0)) { |
498 | st->mem_since_last_sid = 0; |
499 | } |
500 | |
501 | /* Interpolate SID info */ |
502 | if (st->mem_since_last_sid < 32) { |
503 | int_fac = st->mem_since_last_sid << 10; /* Q10 */ |
504 | } else { |
505 | int_fac = 32767; |
506 | } |
507 | /* Q10 * Q15 -> Q10 */ |
508 | int_fac = (int_fac * st->mem_true_sid_period_inv) >> 15; |
509 | |
510 | /* Maximize to 1.0 in Q10 */ |
511 | if (int_fac > 1024) { |
512 | int_fac = 1024; |
513 | } |
514 | int_fac = int_fac << 4; /* Q10 -> Q14 */ |
515 | L_log_en_int = (int_fac * st->mem_log_en) << 1; /* Q14 * Q9 -> Q24 */ |
516 | |
517 | for (i = 0; i < M; i++) { |
518 | /* Q14 * Q15 -> Q14 */ |
519 | isf[i] = (Word16)((int_fac * st->mem_isf[i]) >> 15); |
520 | } |
521 | int_fac = 16384 - int_fac; /* 1-k in Q14 */ |
522 | |
523 | /* ( Q14 * Q9 -> Q24 ) + Q24 -> Q24 */ |
524 | L_log_en_int = L_log_en_int + ((int_fac * st->mem_log_en_prev) << 1); |
525 | |
526 | for (i = 0; i < M; i++) { |
527 | /* Q14 + (Q14 * Q15 -> Q14) -> Q14 */ |
528 | L_tmp = isf[i] + ((int_fac * st->mem_isf_prev[i]) >> 15); |
529 | isf[i] = (Word16)(L_tmp << 1); /* Q14 -> Q15 */ |
530 | } |
531 | |
532 | /* If background noise is non-stationary, insert comfort noise dithering */ |
533 | if (st->mem_cn_dith != 0) { |
534 | D_DTX_cn_dithering(isf, &L_log_en_int, &st->mem_dither_seed); |
535 | } |
536 | |
537 | /* L_log_en_int corresponds to log2(E)+2 in Q24, i.e log2(gain)+1 in Q25 */ |
538 | L_log_en_int = (L_log_en_int >> 9); /* Q25 -> Q16 */ |
539 | |
540 | /* Find integer part */ |
541 | log_en_int_e = (Word16)((L_log_en_int) >> 16); |
542 | |
543 | /* Find fractional part */ |
544 | log_en_int_m = (Word16)((L_log_en_int - (log_en_int_e << 16)) >> 1); |
545 | |
546 | /* |
547 | * Subtract 2 from L_log_en_int in Q9, |
548 | * i.e divide the gain by 2 (energy by 4) |
549 | * Add 16 in order to have the result of pow2 in Q16 |
550 | */ |
551 | log_en_int_e = (Word16)(log_en_int_e + (16 - 1)); |
552 | |
553 | /* level = (Float32)( pow( 2.0f, log_en ) ); */ |
554 | level32 = D_UTIL_pow2(log_en_int_e, log_en_int_m); /* Q16 */ |
555 | exp0 = D_UTIL_norm_l(level32); |
556 | level32 = (level32 << exp0); /* level in Q31 */ |
557 | exp0 = (15 - exp0); |
558 | level = (Word16)(level32 >> 16); /* level in Q15 */ |
559 | |
560 | /* generate white noise vector */ |
561 | for (i = 0; i < L_FRAME; i++) { |
562 | exc2[i] = (Word16)((D_UTIL_random(&(st->mem_cng_seed)) >> 4)); |
563 | } |
564 | |
565 | /* gain = level / sqrt(ener) * sqrt(L_FRAME) */ |
566 | /* energy of generated excitation */ |
567 | ener32 = D_UTIL_dot_product12(exc2, exc2, L_FRAME, &exp); |
568 | D_UTIL_normalised_inverse_sqrt(&ener32, &exp); |
569 | gain = ener32 >> 16; |
570 | gain = (level * gain) >> 15; /* gain in Q15 */ |
571 | |
572 | /* Multiply by sqrt(L_FRAME)=16, i.e. shift left by 4 */ |
573 | exp = (Word16)(exp0 + exp + 4); |
574 | |
575 | if (exp >= 0) { |
576 | for (i = 0; i < L_FRAME; i++) { |
577 | L_tmp = (exc2[i] * gain) >> 15; /* Q0 * Q15 */ |
578 | exc2[i] = (Word16)(L_tmp << exp); |
579 | } |
580 | } else { |
581 | exp = (Word16) - exp; |
582 | |
583 | for (i = 0; i < L_FRAME; i++) { |
584 | L_tmp = (exc2[i] * gain) >> 15; /* Q0 * Q15 */ |
585 | exc2[i] = (Word16)(L_tmp >> exp); |
586 | } |
587 | } |
588 | |
589 | if (new_state == D_DTX_MUTE) { |
590 | /* |
591 | * mute comfort noise as it has been quite a long time since |
592 | * last SID update was performed |
593 | */ |
594 | tmp_int_length = st->mem_since_last_sid; |
595 | |
596 | if (tmp_int_length > 32) { |
597 | tmp_int_length = 32; |
598 | } |
599 | |
600 | /* safety guard against division by zero */ |
601 | if (tmp_int_length <= 0) { |
602 | tmp_int_length = 8; |
603 | } |
604 | st->mem_true_sid_period_inv = D_UTIL_saturate((0x02000000 / (tmp_int_length << 10))); |
605 | st->mem_since_last_sid = 0; |
606 | st->mem_log_en_prev = st->mem_log_en; |
607 | |
608 | /* subtract 1/8 in Q9 (energy), i.e -3/8 dB */ |
609 | st->mem_log_en = D_UTIL_saturate(st->mem_log_en - 64); |
610 | } |
611 | |
612 | /* reset interpolation length timer if data has been updated. */ |
613 | if ((st->mem_sid_frame != 0) && ((st->mem_valid_data != 0) || |
614 | ((st->mem_valid_data == 0) && (st->mem_dtx_hangover_added) != 0))) { |
615 | st->mem_since_last_sid = 0; |
616 | st->mem_data_updated = 1; |
617 | } |
618 | |
619 | return; |
620 | } |
621 | |
622 | |
623 | /* |
624 | * D_DTX_activity_update |
625 | * |
626 | * Parameters: |
627 | * st I/O: state struct |
628 | * isf O: ISF vector |
629 | * exc O: excitation |
630 | * |
631 | * Function: |
632 | * Confort noise generation |
633 | * |
634 | * Returns: |
635 | * void |
636 | */ |
637 | void D_DTX_activity_update(D_DTX_State *st, Word16 isf[], Word16 exc[]) |
638 | { |
639 | |
640 | Word32 L_frame_en, log_en; |
641 | Word32 i; |
642 | Word16 log_en_e, log_en_m; |
643 | |
644 | st->mem_hist_ptr = (Word16)(st->mem_hist_ptr + 1); |
645 | |
646 | if (st->mem_hist_ptr == D_DTX_HIST_SIZE) { |
647 | st->mem_hist_ptr = 0; |
648 | } |
649 | |
650 | memcpy(&st->mem_isf_buf[st->mem_hist_ptr * M], isf, M * sizeof(Word16)); |
651 | |
652 | /* compute log energy based on excitation frame energy in Q0 */ |
653 | L_frame_en = 0; |
654 | |
655 | for (i = 0; i < L_FRAME; i++) { |
656 | L_frame_en = L_frame_en + (exc[i] * exc[i]); |
657 | if (L_frame_en > MAX_31) { |
658 | L_frame_en = MAX_31; |
659 | break; |
660 | } |
661 | } |
662 | |
663 | /* |
664 | * log_en = |
665 | * (Float32)log10(L_frame_en/(Float32)L_FRAME)/(Float32)log10(2.0f); |
666 | */ |
667 | D_UTIL_log2(L_frame_en, &log_en_e, &log_en_m); |
668 | |
669 | /* |
670 | * convert exponent and mantissa to Word16 Q7. |
671 | * Q7 is used to simplify averaging in dtx_enc |
672 | */ |
673 | log_en = log_en_e << 7; /* Q7 */ |
674 | log_en = log_en + (log_en_m >> (15 - 7)); |
675 | |
676 | /* Divide by L_FRAME = 256, i.e subtract 8 in Q7 = 1024 */ |
677 | log_en = log_en - 1024; |
678 | |
679 | /* insert into log energy buffer */ |
680 | st->mem_log_en_buf[st->mem_hist_ptr] = (Word16)log_en; |
681 | |
682 | return; |
683 | } |
684 |