comparison libgsmefr/vad.c @ 110:913fe3c11890

libgsmefr/vad.c: initial import from ETSI code
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 29 Nov 2022 03:01:38 +0000
parents
children 756605c4850f
comparison
equal deleted inserted replaced
109:2361a7d8c1eb 110:913fe3c11890
1 /***************************************************************************
2 *
3 * File Name: vad.c
4 *
5 * Purpose: Contains all functions for voice activity detection, as
6 * described in the high level specification of VAD.
7 *
8 * Below is a listing of all the functions appearing in the file.
9 * The functions are arranged according to their purpose. Under
10 * each heading, the ordering is hierarchical.
11 *
12 * Resetting of static variables of VAD:
13 * reset_vad()
14 *
15 * Main routine of VAD (called by the speech encoder):
16 * vad_computation()
17 * Adaptive filtering and energy computation:
18 * energy_computation()
19 * Averaging of autocorrelation function values:
20 * acf_averaging()
21 * Computation of predictor values:
22 * predictor_values()
23 * schur_recursion()
24 * step_up()
25 * compute_rav1()
26 * Spectral comparison:
27 * spectral_comparison()
28 * Information tone detection:
29 * tone_detection()
30 * step_up()
31 * Threshold adaptation:
32 * threshold_adaptation()
33 * VAD decision:
34 * vad_decision()
35 * VAD hangover addition:
36 * vad_hangover()
37 *
38 * Periodicity detection routine (called by the speech encoder):
39 * periodicity_detection()
40 *
41 **************************************************************************/
42
43 #include "typedef.h"
44 #include "cnst.h"
45 #include "basic_op.h"
46 #include "oper_32b.h"
47 #include "count.h"
48 #include "vad.h"
49
50 /* Constants of VAD hangover addition */
51
52 #define HANGCONST 10
53 #define BURSTCONST 3
54
55 /* Constant of spectral comparison */
56
57 #define STAT_THRESH 3670L /* 0.056 */
58
59 /* Constants of periodicity detection */
60
61 #define LTHRESH 2
62 #define NTHRESH 4
63
64 /* Pseudo floating point representations of constants
65 for threshold adaptation */
66
67 #define M_PTH 32500 /*** 130000.0 ***/
68 #define E_PTH 17
69 #define M_PLEV 21667 /*** 346666.7 ***/
70 #define E_PLEV 19
71 #define M_MARGIN 16927 /*** 69333340 ***/
72 #define E_MARGIN 27
73
74 #define FAC 17203 /* 2.1 */
75
76 /* Constants of tone detection */
77
78 #define FREQTH 3189
79 #define PREDTH 1464
80
81 /* Static variables of VAD */
82
83 static Word16 rvad[9], scal_rvad;
84 static Pfloat thvad;
85 static Word32 L_sacf[27];
86 static Word32 L_sav0[36];
87 static Word16 pt_sacf, pt_sav0;
88 static Word32 L_lastdm;
89 static Word16 adaptcount;
90 static Word16 burstcount, hangcount;
91 static Word16 oldlagcount, veryoldlagcount, oldlag;
92
93 Word16 ptch;
94
95 /*************************************************************************
96 *
97 * FUNCTION NAME: vad_reset
98 *
99 * PURPOSE: Resets the static variables of the VAD to their
100 * initial values
101 *
102 *************************************************************************/
103
104 void vad_reset ()
105 {
106 Word16 i;
107
108 /* Initialize rvad variables */
109 rvad[0] = 0x6000;
110 for (i = 1; i < 9; i++)
111 {
112 rvad[i] = 0;
113 }
114 scal_rvad = 7;
115
116 /* Initialize threshold level */
117 thvad.e = 20; /*** exponent ***/
118 thvad.m = 27083; /*** mantissa ***/
119
120 /* Initialize ACF averaging variables */
121 for (i = 0; i < 27; i++)
122 {
123 L_sacf[i] = 0L;
124 }
125 for (i = 0; i < 36; i++)
126 {
127 L_sav0[i] = 0L;
128 }
129 pt_sacf = 0;
130 pt_sav0 = 0;
131
132 /* Initialize spectral comparison variable */
133 L_lastdm = 0L;
134
135 /* Initialize threshold adaptation variable */
136 adaptcount = 0;
137
138 /* Initialize VAD hangover addition variables */
139 burstcount = 0;
140 hangcount = -1;
141
142 /* Initialize periodicity detection variables */
143 oldlagcount = 0;
144 veryoldlagcount = 0;
145 oldlag = 18;
146
147 ptch = 1;
148
149 return;
150 }
151
152 /****************************************************************************
153 *
154 * FUNCTION: vad_computation
155 *
156 * PURPOSE: Returns a decision as to whether the current frame being
157 * processed by the speech encoder contains speech or not.
158 *
159 * INPUTS: r_h[0..8] autocorrelation of input signal frame (msb)
160 * r_l[0..8] autocorrelation of input signal frame (lsb)
161 * scal_acf scaling factor for the autocorrelations
162 * rc[0..3] speech encoder reflection coefficients
163 * ptch flag to indicate a periodic signal component
164 *
165 * OUTPUTS: none
166 *
167 * RETURN VALUE: vad decision
168 *
169 ***************************************************************************/
170
171 Word16 vad_computation (
172 Word16 r_h[],
173 Word16 r_l[],
174 Word16 scal_acf,
175 Word16 rc[],
176 Word16 ptch
177 )
178 {
179 Word32 L_av0[9], L_av1[9];
180 Word16 vad, vvad, rav1[9], scal_rav1, stat, tone;
181 Pfloat acf0, pvad;
182
183 energy_computation (r_h, scal_acf, rvad, scal_rvad, &acf0, &pvad);
184 acf_averaging (r_h, r_l, scal_acf, L_av0, L_av1);
185 predictor_values (L_av1, rav1, &scal_rav1);
186 stat = spectral_comparison (rav1, scal_rav1, L_av0); move16 ();
187 tone_detection (rc, &tone);
188 threshold_adaptation (stat, ptch, tone, rav1, scal_rav1, pvad, acf0,
189 rvad, &scal_rvad, &thvad);
190 vvad = vad_decision (pvad, thvad); move16 ();
191 vad = vad_hangover (vvad); move16 ();
192
193 return vad;
194 }
195
196 /****************************************************************************
197 *
198 * FUNCTION: energy_computation
199 *
200 * PURPOSE: Computes the input and residual energies of the adaptive
201 * filter in a floating point representation.
202 *
203 * INPUTS: r_h[0..8] autocorrelation of input signal frame (msb)
204 * scal_acf scaling factor for the autocorrelations
205 * rvad[0..8] autocorrelated adaptive filter coefficients
206 * scal_rvad scaling factor for rvad[]
207 *
208 * OUTPUTS: *acf0 signal frame energy (mantissa+exponent)
209 * *pvad filtered signal energy (mantissa+exponent)
210 *
211 * RETURN VALUE: none
212 *
213 ***************************************************************************/
214
215 void energy_computation (
216 Word16 r_h[],
217 Word16 scal_acf,
218 Word16 rvad[],
219 Word16 scal_rvad,
220 Pfloat * acf0,
221 Pfloat * pvad
222 )
223 {
224 Word16 i, temp, norm_prod;
225 Word32 L_temp;
226
227 /* r[0] is always greater than zero (no need to test for r[0] == 0) */
228
229 /* Computation of acf0 (exponent and mantissa) */
230
231 acf0->e = sub (32, scal_acf); move16 ();
232 acf0->m = r_h[0] & 0x7ff8; move16 (); logic16 ();
233
234 /* Computation of pvad (exponent and mantissa) */
235
236 pvad->e = add (acf0->e, 14); move16 ();
237 pvad->e = sub (pvad->e, scal_rvad); move16 ();
238
239 L_temp = 0L; move32 ();
240
241 for (i = 1; i <= 8; i++)
242 {
243 temp = shr (r_h[i], 3);
244 L_temp = L_mac (L_temp, temp, rvad[i]);
245 }
246
247 temp = shr (r_h[0], 3);
248 L_temp = L_add (L_temp, L_shr (L_mult (temp, rvad[0]), 1));
249
250 test ();
251 if (L_temp <= 0L)
252 {
253 L_temp = 1L; move32 ();
254 }
255 norm_prod = norm_l (L_temp);
256 pvad->e = sub (pvad->e, norm_prod); move16 ();
257 pvad->m = extract_h (L_shl (L_temp, norm_prod));
258 move16 ();
259
260 return;
261 }
262
263 /****************************************************************************
264 *
265 * FUNCTION: acf_averaging
266 *
267 * PURPOSE: Computes the arrays L_av0[0..8] and L_av1[0..8].
268 *
269 * INPUTS: r_h[0..8] autocorrelation of input signal frame (msb)
270 * r_l[0..8] autocorrelation of input signal frame (lsb)
271 * scal_acf scaling factor for the autocorrelations
272 *
273 * OUTPUTS: L_av0[0..8] ACF averaged over last four frames
274 * L_av1[0..8] ACF averaged over previous four frames
275 *
276 * RETURN VALUE: none
277 *
278 ***************************************************************************/
279
280 void acf_averaging (
281 Word16 r_h[],
282 Word16 r_l[],
283 Word16 scal_acf,
284 Word32 L_av0[],
285 Word32 L_av1[]
286 )
287 {
288 Word32 L_temp;
289 Word16 scale;
290 Word16 i;
291
292 scale = add (9, scal_acf);
293
294 for (i = 0; i <= 8; i++)
295 {
296 L_temp = L_shr (L_Comp (r_h[i], r_l[i]), scale);
297 L_av0[i] = L_add (L_sacf[i], L_temp); move32 ();
298 L_av0[i] = L_add (L_sacf[i + 9], L_av0[i]); move32 ();
299 L_av0[i] = L_add (L_sacf[i + 18], L_av0[i]); move32 ();
300 L_sacf[pt_sacf + i] = L_temp; move32 ();
301 L_av1[i] = L_sav0[pt_sav0 + i]; move32 ();
302 L_sav0[pt_sav0 + i] = L_av0[i]; move32 ();
303 }
304
305 /* Update the array pointers */
306
307 test ();
308 if (sub (pt_sacf, 18) == 0)
309 {
310 pt_sacf = 0; move16 ();
311 }
312 else
313 {
314 pt_sacf = add (pt_sacf, 9);
315 }
316
317 test ();
318 if (sub (pt_sav0, 27) == 0)
319 {
320 pt_sav0 = 0; move16 ();
321 }
322 else
323 {
324 pt_sav0 = add (pt_sav0, 9);
325 }
326
327 return;
328 }
329
330 /****************************************************************************
331 *
332 * FUNCTION: predictor_values
333 *
334 * PURPOSE: Computes the array rav[0..8] needed for the spectral
335 * comparison and the threshold adaptation.
336 *
337 * INPUTS: L_av1[0..8] ACF averaged over previous four frames
338 *
339 * OUTPUTS: rav1[0..8] ACF obtained from L_av1
340 * *scal_rav1 rav1[] scaling factor
341 *
342 * RETURN VALUE: none
343 *
344 ***************************************************************************/
345
346 void predictor_values (
347 Word32 L_av1[],
348 Word16 rav1[],
349 Word16 *scal_rav1
350 )
351 {
352 Word16 vpar[8], aav1[9];
353
354 schur_recursion (L_av1, vpar);
355 step_up (8, vpar, aav1);
356 compute_rav1 (aav1, rav1, scal_rav1);
357
358 return;
359 }
360
361 /****************************************************************************
362 *
363 * FUNCTION: schur_recursion
364 *
365 * PURPOSE: Uses the Schur recursion to compute adaptive filter
366 * reflection coefficients from an autorrelation function.
367 *
368 * INPUTS: L_av1[0..8] autocorrelation function
369 *
370 * OUTPUTS: vpar[0..7] reflection coefficients
371 *
372 * RETURN VALUE: none
373 *
374 ***************************************************************************/
375
376 void schur_recursion (
377 Word32 L_av1[],
378 Word16 vpar[]
379 )
380 {
381 Word16 acf[9], pp[9], kk[9], temp;
382 Word16 i, k, m, n;
383
384 /*** Schur recursion with 16-bit arithmetic ***/
385
386 test (); move32 ();
387 if (L_av1[0] == 0)
388 {
389 for (i = 0; i < 8; i++)
390 {
391 vpar[i] = 0; move16 ();
392 }
393 return;
394 }
395 temp = norm_l (L_av1[0]);
396
397 for (k = 0; k <= 8; k++)
398 {
399 acf[k] = extract_h (L_shl (L_av1[k], temp)); move16 ();
400 }
401
402 /*** Initialize arrays pp[..] and kk[..] for the recursion: ***/
403
404 for (i = 1; i <= 7; i++)
405 {
406 kk[9 - i] = acf[i]; move16 ();
407 }
408
409 for (i = 0; i <= 8; i++)
410 {
411 pp[i] = acf[i]; move16 ();
412 }
413
414 /*** Compute Parcor coefficients: ***/
415
416 for (n = 0; n < 8; n++)
417 {
418 test ();
419 if ((pp[0] == 0) ||
420 (sub (pp[0], abs_s (pp[1])) < 0))
421 {
422 for (i = n; i < 8; i++)
423 {
424 vpar[i] = 0; move16 ();
425 }
426 return;
427 }
428 vpar[n] = div_s (abs_s (pp[1]), pp[0]); move16 ();
429
430 test (); move16 ();
431 if (pp[1] > 0)
432 {
433 vpar[n] = negate (vpar[n]); move16 ();
434 }
435 test ();
436 if (sub (n, 7) == 0)
437 {
438 return;
439 }
440 /*** Schur recursion: ***/
441
442 pp[0] = add (pp[0], mult_r (pp[1], vpar[n])); move16 ();
443
444 for (m = 1; m <= 7 - n; m++)
445 {
446 pp[m] = add (pp[1 + m], mult_r (kk[9 - m], vpar[n]));
447 move16 ();
448 kk[9 - m] = add (kk[9 - m], mult_r (pp[1 + m], vpar[n]));
449 move16 ();
450 }
451 }
452
453 return;
454 }
455
456 /****************************************************************************
457 *
458 * FUNCTION: step_up
459 *
460 * PURPOSE: Computes the transversal filter coefficients from the
461 * reflection coefficients.
462 *
463 * INPUTS: np filter order (2..8)
464 * vpar[0..np-1] reflection coefficients
465 *
466 * OUTPUTS: aav1[0..np] transversal filter coefficients
467 *
468 * RETURN VALUE: none
469 *
470 ***************************************************************************/
471
472 void step_up (
473 Word16 np,
474 Word16 vpar[],
475 Word16 aav1[]
476 )
477 {
478 Word32 L_coef[9], L_work[9];
479 Word16 temp;
480 Word16 i, m;
481
482 /*** Initialization of the step-up recursion ***/
483
484 L_coef[0] = 0x20000000L; move32 ();
485 L_coef[1] = L_shl (L_deposit_l (vpar[0]), 14); move32 ();
486
487 /*** Loop on the LPC analysis order: ***/
488
489 for (m = 2; m <= np; m++)
490 {
491 for (i = 1; i < m; i++)
492 {
493 temp = extract_h (L_coef[m - i]);
494 L_work[i] = L_mac (L_coef[i], vpar[m - 1], temp); move32 ();
495 }
496
497 for (i = 1; i < m; i++)
498 {
499 L_coef[i] = L_work[i]; move32 ();
500 }
501
502 L_coef[m] = L_shl (L_deposit_l (vpar[m - 1]), 14); move32 ();
503 }
504
505 /*** Keep the aav1[0..np] in 15 bits ***/
506
507 for (i = 0; i <= np; i++)
508 {
509 aav1[i] = extract_h (L_shr (L_coef[i], 3)); move32 ();
510 }
511
512 return;
513 }
514
515 /****************************************************************************
516 *
517 * FUNCTION: compute_rav1
518 *
519 * PURPOSE: Computes the autocorrelation function of the adaptive
520 * filter coefficients.
521 *
522 * INPUTS: aav1[0..8] adaptive filter coefficients
523 *
524 * OUTPUTS: rav1[0..8] ACF of aav1
525 * *scal_rav1 rav1[] scaling factor
526 *
527 * RETURN VALUE: none
528 *
529 ***************************************************************************/
530
531 void compute_rav1 (
532 Word16 aav1[],
533 Word16 rav1[],
534 Word16 *scal_rav1
535 )
536 {
537 Word32 L_work[9];
538 Word16 i, k;
539
540 /*** Computation of the rav1[0..8] ***/
541
542 for (i = 0; i <= 8; i++)
543 {
544 L_work[i] = 0L; move32 ();
545
546 for (k = 0; k <= 8 - i; k++)
547 {
548 L_work[i] = L_mac (L_work[i], aav1[k], aav1[k + i]); move32 ();
549 }
550 }
551
552 test (); move32 ();
553 if (L_work[0] == 0L)
554 {
555 *scal_rav1 = 0; move16 ();
556 }
557 else
558 {
559 *scal_rav1 = norm_l (L_work[0]);
560 }
561
562 for (i = 0; i <= 8; i++)
563 {
564 rav1[i] = extract_h (L_shl (L_work[i], *scal_rav1)); move16 ();
565 }
566
567 return;
568 }
569
570 /****************************************************************************
571 *
572 * FUNCTION: spectral_comparison
573 *
574 * PURPOSE: Computes the stat flag needed for the threshold
575 * adaptation decision.
576 *
577 * INPUTS: rav1[0..8] ACF obtained from L_av1
578 * *scal_rav1 rav1[] scaling factor
579 * L_av0[0..8] ACF averaged over last four frames
580 *
581 * OUTPUTS: none
582 *
583 * RETURN VALUE: flag to indicate spectral stationarity
584 *
585 ***************************************************************************/
586
587 Word16 spectral_comparison (
588 Word16 rav1[],
589 Word16 scal_rav1,
590 Word32 L_av0[]
591 )
592 {
593 Word32 L_dm, L_sump, L_temp;
594 Word16 stat, sav0[9], shift, divshift, temp;
595 Word16 i;
596
597 /*** Re-normalize L_av0[0..8] ***/
598
599 test (); move32 ();
600 if (L_av0[0] == 0L)
601 {
602 for (i = 0; i <= 8; i++)
603 {
604 sav0[i] = 0x0fff; /* 4095 */ move16 ();
605 }
606 }
607 else
608 {
609 shift = sub (norm_l (L_av0[0]), 3);
610 for (i = 0; i <= 8; i++)
611 {
612 sav0[i] = extract_h (L_shl (L_av0[i], shift)); move16 ();
613 }
614 }
615
616 /*** Compute partial sum of dm ***/
617
618 L_sump = 0L; move32 ();
619 for (i = 1; i <= 8; i++)
620 {
621 L_sump = L_mac (L_sump, rav1[i], sav0[i]);
622 }
623
624 /*** Compute the division of the partial sum by sav0[0] ***/
625
626 test ();
627 if (L_sump < 0L)
628 {
629 L_temp = L_negate (L_sump);
630 }
631 else
632 {
633 L_temp = L_sump; move32 ();
634 }
635
636 test ();
637 if (L_temp == 0L)
638 {
639 L_dm = 0L; move32 ();
640 shift = 0; move16 ();
641 }
642 else
643 {
644 sav0[0] = shl (sav0[0], 3); move16 ();
645 shift = norm_l (L_temp);
646 temp = extract_h (L_shl (L_temp, shift));
647
648 test ();
649 if (sub (sav0[0], temp) >= 0)
650 {
651 divshift = 0; move16 ();
652 temp = div_s (temp, sav0[0]);
653 }
654 else
655 {
656 divshift = 1; move16 ();
657 temp = sub (temp, sav0[0]);
658 temp = div_s (temp, sav0[0]);
659 }
660
661 test ();
662 if (sub (divshift, 1) == 0)
663 {
664 L_dm = 0x8000L; move32 ();
665 }
666 else
667 {
668 L_dm = 0L; move32 ();
669 }
670
671 L_dm = L_shl (L_add (L_dm, L_deposit_l (temp)), 1);
672
673 test ();
674 if (L_sump < 0L)
675 {
676 L_dm = L_negate (L_dm);
677 }
678 }
679
680 /*** Re-normalization and final computation of L_dm ***/
681
682 L_dm = L_shl (L_dm, 14);
683 L_dm = L_shr (L_dm, shift);
684 L_dm = L_add (L_dm, L_shl (L_deposit_l (rav1[0]), 11));
685 L_dm = L_shr (L_dm, scal_rav1);
686
687 /*** Compute the difference and save L_dm ***/
688
689 L_temp = L_sub (L_dm, L_lastdm);
690 L_lastdm = L_dm; move32 ();
691
692 test ();
693 if (L_temp < 0L)
694 {
695 L_temp = L_negate (L_temp);
696 }
697 /*** Evaluation of the stat flag ***/
698
699 L_temp = L_sub (L_temp, STAT_THRESH);
700
701 test ();
702 if (L_temp < 0L)
703 {
704 stat = 1; move16 ();
705 }
706 else
707 {
708 stat = 0; move16 ();
709 }
710
711 return stat;
712 }
713
714 /****************************************************************************
715 *
716 * FUNCTION: threshold_adaptation
717 *
718 * PURPOSE: Evaluates the secondary VAD decision. If speech is not
719 * present then the noise model rvad and adaptive threshold
720 * thvad are updated.
721 *
722 * INPUTS: stat flag to indicate spectral stationarity
723 * ptch flag to indicate a periodic signal component
724 * tone flag to indicate a tone signal component
725 * rav1[0..8] ACF obtained from L_av1
726 * scal_rav1 rav1[] scaling factor
727 * pvad filtered signal energy (mantissa+exponent)
728 * acf0 signal frame energy (mantissa+exponent)
729 *
730 * OUTPUTS: rvad[0..8] autocorrelated adaptive filter coefficients
731 * *scal_rvad rvad[] scaling factor
732 * *thvad decision threshold (mantissa+exponent)
733 *
734 * RETURN VALUE: none
735 *
736 ***************************************************************************/
737
738 void threshold_adaptation (
739 Word16 stat,
740 Word16 ptch,
741 Word16 tone,
742 Word16 rav1[],
743 Word16 scal_rav1,
744 Pfloat pvad,
745 Pfloat acf0,
746 Word16 rvad[],
747 Word16 *scal_rvad,
748 Pfloat * thvad
749 )
750 {
751 Word16 comp, comp2;
752 Word32 L_temp;
753 Word16 temp;
754 Pfloat p_temp;
755 Word16 i;
756
757 comp = 0; move16 ();
758
759 /*** Test if acf0 < pth; if yes set thvad to plev ***/
760
761 test ();
762 if (sub (acf0.e, E_PTH) < 0)
763 {
764 comp = 1; move16 ();
765 }
766 test (); test ();
767 if ((sub (acf0.e, E_PTH) == 0) && (sub (acf0.m, M_PTH) < 0))
768 {
769 comp = 1; move16 ();
770 }
771 test ();
772 if (sub (comp, 1) == 0)
773 {
774 thvad->e = E_PLEV; move16 ();
775 thvad->m = M_PLEV; move16 ();
776
777 return;
778 }
779 /*** Test if an adaption is required ***/
780
781 test ();
782 if (sub (ptch, 1) == 0)
783 {
784 comp = 1; move16 ();
785 }
786 test ();
787 if (stat == 0)
788 {
789 comp = 1; move16 ();
790 }
791 test ();
792 if (sub (tone, 1) == 0)
793 {
794 comp = 1; move16 ();
795 }
796 test ();
797 if (sub (comp, 1) == 0)
798 {
799 adaptcount = 0; move16 ();
800 return;
801 }
802 /*** Increment adaptcount ***/
803
804 adaptcount = add (adaptcount, 1);
805 test ();
806 if (sub (adaptcount, 8) <= 0)
807 {
808 return;
809 }
810 /*** computation of thvad-(thvad/dec) ***/
811
812 thvad->m = sub (thvad->m, shr (thvad->m, 5)); move16 ();
813
814 test ();
815 if (sub (thvad->m, 0x4000) < 0)
816 {
817 thvad->m = shl (thvad->m, 1); move16 ();
818 thvad->e = sub (thvad->e, 1); move16 ();
819 }
820 /*** computation of pvad*fac ***/
821
822 L_temp = L_mult (pvad.m, FAC);
823 L_temp = L_shr (L_temp, 15);
824 p_temp.e = add (pvad.e, 1); move16 ();
825
826 test ();
827 if (L_temp > 0x7fffL)
828 {
829 L_temp = L_shr (L_temp, 1);
830 p_temp.e = add (p_temp.e, 1); move16 ();
831 }
832 p_temp.m = extract_l (L_temp); move16 ();
833
834 /*** test if thvad < pvad*fac ***/
835
836 test ();
837 if (sub (thvad->e, p_temp.e) < 0)
838 {
839 comp = 1; move16 ();
840 }
841 test (); test ();
842 if ((sub (thvad->e, p_temp.e) == 0) &&
843 (sub (thvad->m, p_temp.m) < 0))
844 {
845 comp = 1; move16 ();
846 }
847 /*** compute minimum(thvad+(thvad/inc), pvad*fac) when comp = 1 ***/
848
849 test ();
850 if (sub (comp, 1) == 0)
851 {
852 /*** compute thvad + (thvad/inc) ***/
853
854 L_temp = L_add (L_deposit_l (thvad->m),
855 L_deposit_l (shr (thvad->m, 4)));
856
857 test ();
858 if (L_sub (L_temp, 0x7fffL) > 0)
859 {
860 thvad->m = extract_l (L_shr (L_temp, 1)); move16 ();
861 thvad->e = add (thvad->e, 1); move16 ();
862 }
863 else
864 {
865 thvad->m = extract_l (L_temp); move16 ();
866 }
867
868 comp2 = 0; move16 ();
869
870 test ();
871 if (sub (p_temp.e, thvad->e) < 0)
872 {
873 comp2 = 1; move16 ();
874 }
875 test (); test ();
876 if ((sub (p_temp.e, thvad->e) == 0) &&
877 (sub (p_temp.m, thvad->m) < 0))
878 {
879 comp2 = 1; move16 ();
880 }
881 test ();
882 if (sub (comp2, 1) == 0)
883 {
884 thvad->e = p_temp.e;move16 ();
885 thvad->m = p_temp.m;move16 ();
886 }
887 }
888 /*** compute pvad + margin ***/
889
890 test ();
891 if (sub (pvad.e, E_MARGIN) == 0)
892 {
893 L_temp = L_add (L_deposit_l (pvad.m), L_deposit_l (M_MARGIN));
894 p_temp.m = extract_l (L_shr (L_temp, 1)); move16 ();
895 p_temp.e = add (pvad.e, 1); move16 ();
896 }
897 else
898 {
899 test ();
900 if (sub (pvad.e, E_MARGIN) > 0)
901 {
902 temp = sub (pvad.e, E_MARGIN);
903 temp = shr (M_MARGIN, temp);
904 L_temp = L_add (L_deposit_l (pvad.m), L_deposit_l (temp));
905
906 test ();
907 if (L_sub (L_temp, 0x7fffL) > 0)
908 {
909 p_temp.e = add (pvad.e, 1); move16 ();
910 p_temp.m = extract_l (L_shr (L_temp, 1));
911 move16 ();
912 }
913 else
914 {
915 p_temp.e = pvad.e; move16 ();
916 p_temp.m = extract_l (L_temp); move16 ();
917 }
918 }
919 else
920 {
921 temp = sub (E_MARGIN, pvad.e);
922 temp = shr (pvad.m, temp);
923 L_temp = L_add (L_deposit_l (M_MARGIN), L_deposit_l (temp));
924
925 test ();
926 if (L_sub (L_temp, 0x7fffL) > 0)
927 {
928 p_temp.e = add (E_MARGIN, 1); move16 ();
929 p_temp.m = extract_l (L_shr (L_temp, 1));
930 move16 ();
931 }
932 else
933 {
934 p_temp.e = E_MARGIN; move16 ();
935 p_temp.m = extract_l (L_temp); move16 ();
936 }
937 }
938 }
939
940 /*** Test if thvad > pvad + margin ***/
941
942 comp = 0; move16 ();
943
944 test ();
945 if (sub (thvad->e, p_temp.e) > 0)
946 {
947 comp = 1; move16 ();
948 }
949 test (); test ();
950 if ((sub (thvad->e, p_temp.e) == 0) &&
951 (sub (thvad->m, p_temp.m) > 0))
952 {
953 comp = 1; move16 ();
954 }
955 test ();
956 if (sub (comp, 1) == 0)
957 {
958 thvad->e = p_temp.e; move16 ();
959 thvad->m = p_temp.m; move16 ();
960 }
961 /*** Normalise and retain rvad[0..8] in memory ***/
962
963 *scal_rvad = scal_rav1; move16 ();
964
965 for (i = 0; i <= 8; i++)
966 {
967 rvad[i] = rav1[i]; move16 ();
968 }
969
970 /*** Set adaptcount to adp + 1 ***/
971
972 adaptcount = 9; move16 ();
973
974 return;
975 }
976
977 /****************************************************************************
978 *
979 * FUNCTION: tone_detection
980 *
981 * PURPOSE: Computes the tone flag needed for the threshold
982 * adaptation decision.
983 *
984 * INPUTS: rc[0..3] reflection coefficients calculated in the
985 * speech encoder short term predictor
986 *
987 * OUTPUTS: *tone flag to indicate a periodic signal component
988 *
989 * RETURN VALUE: none
990 *
991 ***************************************************************************/
992
993 void tone_detection (
994 Word16 rc[],
995 Word16 *tone
996 )
997 {
998 Word32 L_num, L_den, L_temp;
999 Word16 temp, prederr, a[3];
1000 Word16 i;
1001
1002 *tone = 0; move16 ();
1003
1004 /*** Calculate filter coefficients ***/
1005
1006 step_up (2, rc, a);
1007
1008 /*** Calculate ( a[1] * a[1] ) ***/
1009
1010 temp = shl (a[1], 3);
1011 L_den = L_mult (temp, temp);
1012
1013 /*** Calculate ( 4*a[2] - a[1]*a[1] ) ***/
1014
1015 L_temp = L_shl (L_deposit_h (a[2]), 3);
1016 L_num = L_sub (L_temp, L_den);
1017
1018 /*** Check if pole frequency is less than 385 Hz ***/
1019
1020 test ();
1021 if (L_num <= 0)
1022 {
1023 return;
1024 }
1025 test (); move16 ();
1026 if (a[1] < 0)
1027 {
1028 temp = extract_h (L_den);
1029 L_den = L_mult (temp, FREQTH);
1030
1031 L_temp = L_sub (L_num, L_den);
1032
1033 test ();
1034 if (L_temp < 0)
1035 {
1036 return;
1037 }
1038 }
1039 /*** Calculate normalised prediction error ***/
1040
1041 prederr = 0x7fff; move16 ();
1042
1043 for (i = 0; i < 4; i++)
1044 {
1045 temp = mult (rc[i], rc[i]);
1046 temp = sub (0x7fff, temp);
1047 prederr = mult (prederr, temp);
1048 }
1049
1050 /*** Test if prediction error is smaller than threshold ***/
1051
1052 temp = sub (prederr, PREDTH);
1053
1054 test ();
1055 if (temp < 0)
1056 {
1057 *tone = 1; move16 ();
1058 }
1059 return;
1060 }
1061
1062 /****************************************************************************
1063 *
1064 * FUNCTION: vad_decision
1065 *
1066 * PURPOSE: Computes the VAD decision based on the comparison of the
1067 * floating point representations of pvad and thvad.
1068 *
1069 * INPUTS: pvad filtered signal energy (mantissa+exponent)
1070 * thvad decision threshold (mantissa+exponent)
1071 *
1072 * OUTPUTS: none
1073 *
1074 * RETURN VALUE: vad decision before hangover is added
1075 *
1076 ***************************************************************************/
1077
1078 Word16 vad_decision (
1079 Pfloat pvad,
1080 Pfloat thvad
1081 )
1082 {
1083 Word16 vvad;
1084
1085 test (); test (); test ();
1086 if (sub (pvad.e, thvad.e) > 0)
1087 {
1088 vvad = 1; move16 ();
1089 }
1090 else if ((sub (pvad.e, thvad.e) == 0) &&
1091 (sub (pvad.m, thvad.m) > 0))
1092 {
1093 vvad = 1; move16 ();
1094 }
1095 else
1096 {
1097 vvad = 0; move16 ();
1098 }
1099
1100 return vvad;
1101 }
1102
1103 /****************************************************************************
1104 *
1105 * FUNCTION: vad_hangover
1106 *
1107 * PURPOSE: Computes the final VAD decision for the current frame
1108 * being processed.
1109 *
1110 * INPUTS: vvad vad decision before hangover is added
1111 *
1112 * OUTPUTS: none
1113 *
1114 * RETURN VALUE: vad decision after hangover is added
1115 *
1116 ***************************************************************************/
1117
1118 Word16 vad_hangover (
1119 Word16 vvad
1120 )
1121 {
1122 test ();
1123 if (sub (vvad, 1) == 0)
1124 {
1125 burstcount = add (burstcount, 1);
1126 }
1127 else
1128 {
1129 burstcount = 0; move16 ();
1130 }
1131
1132 test ();
1133 if (sub (burstcount, BURSTCONST) >= 0)
1134 {
1135 hangcount = HANGCONST; move16 ();
1136 burstcount = BURSTCONST;move16 ();
1137 }
1138 test ();
1139 if (hangcount >= 0)
1140 {
1141 hangcount = sub (hangcount, 1);
1142 return 1; /* vad = 1 */
1143 }
1144 return vvad; /* vad = vvad */
1145 }
1146
1147 /****************************************************************************
1148 *
1149 * FUNCTION: periodicity_update
1150 *
1151 * PURPOSE: Computes the ptch flag needed for the threshold
1152 * adaptation decision for the next frame.
1153 *
1154 * INPUTS: lags[0..1] speech encoder long term predictor lags
1155 *
1156 * OUTPUTS: *ptch Boolean voiced / unvoiced decision
1157 *
1158 * RETURN VALUE: none
1159 *
1160 ***************************************************************************/
1161
1162 void periodicity_update (
1163 Word16 lags[],
1164 Word16 *ptch
1165 )
1166 {
1167 Word16 minlag, maxlag, lagcount, temp;
1168 Word16 i;
1169
1170 /*** Run loop for the two halves in the frame ***/
1171
1172 lagcount = 0; move16 ();
1173
1174 for (i = 0; i <= 1; i++)
1175 {
1176 /*** Search the maximum and minimum of consecutive lags ***/
1177
1178 test ();
1179 if (sub (oldlag, lags[i]) > 0)
1180 {
1181 minlag = lags[i]; move16 ();
1182 maxlag = oldlag; move16 ();
1183 }
1184 else
1185 {
1186 minlag = oldlag; move16 ();
1187 maxlag = lags[i]; move16 ();
1188 }
1189
1190 temp = sub (maxlag, minlag);
1191
1192 test ();
1193 if (sub (temp, LTHRESH) < 0)
1194 {
1195 lagcount = add (lagcount, 1);
1196 }
1197 /*** Save the current LTP lag ***/
1198
1199 oldlag = lags[i]; move16 ();
1200 }
1201
1202 /*** Update the veryoldlagcount and oldlagcount ***/
1203
1204 veryoldlagcount = oldlagcount;
1205 move16 ();
1206 oldlagcount = lagcount; move16 ();
1207
1208 /*** Make ptch decision ready for next frame ***/
1209
1210 temp = add (oldlagcount, veryoldlagcount);
1211
1212 test ();
1213 if (sub (temp, NTHRESH) >= 0)
1214 {
1215 *ptch = 1; move16 ();
1216 }
1217 else
1218 {
1219 *ptch = 0; move16 ();
1220 }
1221
1222 return;
1223 }