summaryrefslogtreecommitdiff
path: root/audio_codec/libamr/dec_dtx.c (plain)
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 */
46int 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 */
96int 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 */
130void 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 */
178UWord8 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 */
297static 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 */
367void 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 */
637void 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