1e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent/*
2e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *
4e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  Use of this source code is governed by a BSD-style license
5e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  that can be found in the LICENSE file in the root of the source
6e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  tree. An additional intellectual property rights grant can be found
7e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  in the file PATENTS.  All contributing project authors may
8e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  be found in the AUTHORS file in the root of the source tree.
9e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent */
10e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
11e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include "noise_suppression_x.h"
12e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
13e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include <assert.h>
14e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include <math.h>
15e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include <string.h>
16e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include <stdlib.h>
17e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
18e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include "nsx_core.h"
19e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
20e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Skip first frequency bins during estimation. (0 <= value < 64)
21e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const int kStartBand = 5;
22e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
23e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Rounding
24e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kRoundTable[16] = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
25e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        2048, 4096, 8192, 16384};
26e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
27e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Constants to compensate for shifting signal log(2^shifts).
28e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kLogTable[9] = {0, 177, 355, 532, 710, 887, 1065, 1242, 1420};
29e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
30e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kCounterDiv[201] = {32767, 16384, 10923, 8192, 6554, 5461, 4681,
31e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        4096, 3641, 3277, 2979, 2731, 2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560,
32e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        1489, 1425, 1365, 1311, 1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910,
33e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        886, 862, 840, 819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618,
34e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        607, 596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475, 468,
35e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390, 386, 381, 377,
36e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331, 328, 324, 321, 318, 315,
37e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        312, 309, 306, 303, 301, 298, 295, 293, 290, 287, 285, 282, 280, 278, 275, 273, 271,
38e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        269, 266, 264, 262, 260, 258, 256, 254, 252, 250, 248, 246, 245, 243, 241, 239, 237,
39e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        236, 234, 232, 231, 229, 228, 226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211,
40e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        210, 209, 207, 206, 205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191,
41e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173,
42e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163};
43e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
44e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kLogTableFrac[256] = {
45e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent      0,   1,   3,   4,   6,   7,   9,  10,  11,  13,  14,  16,  17,  18,  20,  21,
46e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     22,  24,  25,  26,  28,  29,  30,  32,  33,  34,  36,  37,  38,  40,  41,  42,
47e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     44,  45,  46,  47,  49,  50,  51,  52,  54,  55,  56,  57,  59,  60,  61,  62,
48e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     63,  65,  66,  67,  68,  69,  71,  72,  73,  74,  75,  77,  78,  79,  80,  81,
49e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     82,  84,  85,  86,  87,  88,  89,  90,  92,  93,  94,  95,  96,  97,  98,  99,
50e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 117,
51e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
52e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
53e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
54e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178,
55e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 192,
56e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206,
57e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    207, 208, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219,
58e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231,
59e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    232, 233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244,
60e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255
61e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
62e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
63e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kPowTableFrac[1024] = {
64e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    0,    1,    1,    2,    3,    3,    4,    5,
65e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    6,    6,    7,    8,    8,    9,   10,   10,
66e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   11,   12,   13,   13,   14,   15,   15,   16,
67e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   17,   17,   18,   19,   20,   20,   21,   22,
68e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   22,   23,   24,   25,   25,   26,   27,   27,
69e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   28,   29,   30,   30,   31,   32,   32,   33,
70e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   34,   35,   35,   36,   37,   37,   38,   39,
71e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   40,   40,   41,   42,   42,   43,   44,   45,
72e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   45,   46,   47,   48,   48,   49,   50,   50,
73e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   51,   52,   53,   53,   54,   55,   56,   56,
74e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   57,   58,   58,   59,   60,   61,   61,   62,
75e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   63,   64,   64,   65,   66,   67,   67,   68,
76e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   69,   69,   70,   71,   72,   72,   73,   74,
77e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   75,   75,   76,   77,   78,   78,   79,   80,
78e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   81,   81,   82,   83,   84,   84,   85,   86,
79e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   87,   87,   88,   89,   90,   90,   91,   92,
80e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   93,   93,   94,   95,   96,   96,   97,   98,
81e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent   99,  100,  100,  101,  102,  103,  103,  104,
82e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  105,  106,  106,  107,  108,  109,  109,  110,
83e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  111,  112,  113,  113,  114,  115,  116,  116,
84e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  117,  118,  119,  119,  120,  121,  122,  123,
85e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  123,  124,  125,  126,  126,  127,  128,  129,
86e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  130,  130,  131,  132,  133,  133,  134,  135,
87e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  136,  137,  137,  138,  139,  140,  141,  141,
88e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  142,  143,  144,  144,  145,  146,  147,  148,
89e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  148,  149,  150,  151,  152,  152,  153,  154,
90e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  155,  156,  156,  157,  158,  159,  160,  160,
91e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  161,  162,  163,  164,  164,  165,  166,  167,
92e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  168,  168,  169,  170,  171,  172,  173,  173,
93e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  174,  175,  176,  177,  177,  178,  179,  180,
94e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  181,  181,  182,  183,  184,  185,  186,  186,
95e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  187,  188,  189,  190,  190,  191,  192,  193,
96e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  194,  195,  195,  196,  197,  198,  199,  200,
97e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  200,  201,  202,  203,  204,  205,  205,  206,
98e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  207,  208,  209,  210,  210,  211,  212,  213,
99e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  214,  215,  215,  216,  217,  218,  219,  220,
100e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  220,  221,  222,  223,  224,  225,  225,  226,
101e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  227,  228,  229,  230,  231,  231,  232,  233,
102e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  234,  235,  236,  237,  237,  238,  239,  240,
103e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  241,  242,  243,  243,  244,  245,  246,  247,
104e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  248,  249,  249,  250,  251,  252,  253,  254,
105e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  255,  255,  256,  257,  258,  259,  260,  261,
106e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  262,  262,  263,  264,  265,  266,  267,  268,
107e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  268,  269,  270,  271,  272,  273,  274,  275,
108e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  276,  276,  277,  278,  279,  280,  281,  282,
109e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  283,  283,  284,  285,  286,  287,  288,  289,
110e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  290,  291,  291,  292,  293,  294,  295,  296,
111e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  297,  298,  299,  299,  300,  301,  302,  303,
112e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  304,  305,  306,  307,  308,  308,  309,  310,
113e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  311,  312,  313,  314,  315,  316,  317,  318,
114e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  318,  319,  320,  321,  322,  323,  324,  325,
115e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  326,  327,  328,  328,  329,  330,  331,  332,
116e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  333,  334,  335,  336,  337,  338,  339,  339,
117e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  340,  341,  342,  343,  344,  345,  346,  347,
118e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  348,  349,  350,  351,  352,  352,  353,  354,
119e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  355,  356,  357,  358,  359,  360,  361,  362,
120e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  363,  364,  365,  366,  367,  367,  368,  369,
121e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  370,  371,  372,  373,  374,  375,  376,  377,
122e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  378,  379,  380,  381,  382,  383,  384,  385,
123e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  385,  386,  387,  388,  389,  390,  391,  392,
124e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  393,  394,  395,  396,  397,  398,  399,  400,
125e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  401,  402,  403,  404,  405,  406,  407,  408,
126e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  409,  410,  410,  411,  412,  413,  414,  415,
127e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  416,  417,  418,  419,  420,  421,  422,  423,
128e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  424,  425,  426,  427,  428,  429,  430,  431,
129e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  432,  433,  434,  435,  436,  437,  438,  439,
130e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  440,  441,  442,  443,  444,  445,  446,  447,
131e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  448,  449,  450,  451,  452,  453,  454,  455,
132e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  456,  457,  458,  459,  460,  461,  462,  463,
133e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  464,  465,  466,  467,  468,  469,  470,  471,
134e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  472,  473,  474,  475,  476,  477,  478,  479,
135e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  480,  481,  482,  483,  484,  485,  486,  487,
136e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  488,  489,  490,  491,  492,  493,  494,  495,
137e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  496,  498,  499,  500,  501,  502,  503,  504,
138e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  505,  506,  507,  508,  509,  510,  511,  512,
139e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  513,  514,  515,  516,  517,  518,  519,  520,
140e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  521,  522,  523,  525,  526,  527,  528,  529,
141e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  530,  531,  532,  533,  534,  535,  536,  537,
142e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  538,  539,  540,  541,  542,  544,  545,  546,
143e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  547,  548,  549,  550,  551,  552,  553,  554,
144e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  555,  556,  557,  558,  560,  561,  562,  563,
145e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  564,  565,  566,  567,  568,  569,  570,  571,
146e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  572,  574,  575,  576,  577,  578,  579,  580,
147e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  581,  582,  583,  584,  585,  587,  588,  589,
148e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  590,  591,  592,  593,  594,  595,  596,  597,
149e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  599,  600,  601,  602,  603,  604,  605,  606,
150e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  607,  608,  610,  611,  612,  613,  614,  615,
151e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  616,  617,  618,  620,  621,  622,  623,  624,
152e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  625,  626,  627,  628,  630,  631,  632,  633,
153e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  634,  635,  636,  637,  639,  640,  641,  642,
154e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  643,  644,  645,  646,  648,  649,  650,  651,
155e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  652,  653,  654,  656,  657,  658,  659,  660,
156e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  661,  662,  664,  665,  666,  667,  668,  669,
157e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  670,  672,  673,  674,  675,  676,  677,  678,
158e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  680,  681,  682,  683,  684,  685,  687,  688,
159e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  689,  690,  691,  692,  693,  695,  696,  697,
160e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  698,  699,  700,  702,  703,  704,  705,  706,
161e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  708,  709,  710,  711,  712,  713,  715,  716,
162e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  717,  718,  719,  720,  722,  723,  724,  725,
163e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  726,  728,  729,  730,  731,  732,  733,  735,
164e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  736,  737,  738,  739,  741,  742,  743,  744,
165e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  745,  747,  748,  749,  750,  751,  753,  754,
166e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  755,  756,  757,  759,  760,  761,  762,  763,
167e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  765,  766,  767,  768,  770,  771,  772,  773,
168e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  774,  776,  777,  778,  779,  780,  782,  783,
169e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  784,  785,  787,  788,  789,  790,  792,  793,
170e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  794,  795,  796,  798,  799,  800,  801,  803,
171e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  804,  805,  806,  808,  809,  810,  811,  813,
172e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  814,  815,  816,  818,  819,  820,  821,  823,
173e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  824,  825,  826,  828,  829,  830,  831,  833,
174e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  834,  835,  836,  838,  839,  840,  841,  843,
175e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  844,  845,  846,  848,  849,  850,  851,  853,
176e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  854,  855,  857,  858,  859,  860,  862,  863,
177e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  864,  866,  867,  868,  869,  871,  872,  873,
178e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  874,  876,  877,  878,  880,  881,  882,  883,
179e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  885,  886,  887,  889,  890,  891,  893,  894,
180e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  895,  896,  898,  899,  900,  902,  903,  904,
181e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  906,  907,  908,  909,  911,  912,  913,  915,
182e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  916,  917,  919,  920,  921,  923,  924,  925,
183e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  927,  928,  929,  931,  932,  933,  935,  936,
184e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  937,  938,  940,  941,  942,  944,  945,  946,
185e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  948,  949,  950,  952,  953,  955,  956,  957,
186e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  959,  960,  961,  963,  964,  965,  967,  968,
187e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  969,  971,  972,  973,  975,  976,  977,  979,
188e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  980,  981,  983,  984,  986,  987,  988,  990,
189e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent  991,  992,  994,  995,  996,  998,  999, 1001,
190e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 1002, 1003, 1005, 1006, 1007, 1009, 1010, 1012,
191e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 1013, 1014, 1016, 1017, 1018, 1020, 1021, 1023
192e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
193e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
194e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kIndicatorTable[17] = {0, 2017, 3809, 5227, 6258, 6963, 7424, 7718,
195e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187};
196e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
197e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// hybrib Hanning & flat window
198e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kBlocks80w128x[128] = {
199e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        0,    536,   1072,   1606,   2139,   2669,   3196,   3720,   4240,   4756,   5266,
200e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     5771,   6270,   6762,   7246,   7723,   8192,   8652,   9102,   9543,   9974,  10394,
201e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    10803,  11200,  11585,  11958,  12318,  12665,  12998,  13318,  13623,  13913,  14189,
202e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    14449,  14694,  14924,  15137,  15334,  15515,  15679,  15826,  15956,  16069,  16165,
203e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16244,  16305,  16349,  16375,  16384,  16384,  16384,  16384,  16384,  16384,  16384,
204e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,
205e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,
206e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16384,  16384,  16384,  16384,  16375,  16349,  16305,  16244,  16165,  16069,  15956,
207e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    15826,  15679,  15515,  15334,  15137,  14924,  14694,  14449,  14189,  13913,  13623,
208e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    13318,  12998,  12665,  12318,  11958,  11585,  11200,  10803,  10394,   9974,   9543,
209e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     9102,   8652,   8192,   7723,   7246,   6762,   6270,   5771,   5266,   4756,   4240,
210e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     3720,   3196,   2669,   2139,   1606,   1072,    536
211e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
212e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
213e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// hybrib Hanning & flat window
214e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kBlocks160w256x[256] = {
215e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    0,   268,   536,   804,  1072,  1339,  1606,  1872,
216e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 2139,  2404,  2669,  2933,  3196,  3459,  3720,  3981,
217e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 4240,  4499,  4756,  5012,  5266,  5520,  5771,  6021,
218e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 6270,  6517,  6762,  7005,  7246,  7486,  7723,  7959,
219e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 8192,  8423,  8652,  8878,  9102,  9324,  9543,  9760,
220e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 9974, 10185, 10394, 10600, 10803, 11003, 11200, 11394,
221e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent11585, 11773, 11958, 12140, 12318, 12493, 12665, 12833,
222e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053,
223e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent14189, 14321, 14449, 14574, 14694, 14811, 14924, 15032,
224e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent15137, 15237, 15334, 15426, 15515, 15599, 15679, 15754,
225e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207,
226e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382,
227e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
228e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
229e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
230e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
231e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
232e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
233e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
234e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
235e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16384, 16382, 16375, 16364, 16349, 16329, 16305, 16277,
236e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893,
237e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237,
238e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent15137, 15032, 14924, 14811, 14694, 14574, 14449, 14321,
239e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent14189, 14053, 13913, 13770, 13623, 13472, 13318, 13160,
240e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773,
241e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent11585, 11394, 11200, 11003, 10803, 10600, 10394, 10185,
242e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 9974,  9760,  9543,  9324,  9102,  8878,  8652,  8423,
243e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 8192,  7959,  7723,  7486,  7246,  7005,  6762,  6517,
244e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 6270,  6021,  5771,  5520,  5266,  5012,  4756,  4499,
245e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 4240,  3981,  3720,  3459,  3196,  2933,  2669,  2404,
246e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent 2139,  1872,  1606,  1339,  1072,   804,   536,   268
247e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
248e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
249e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Gain factor table: Input value in Q8 and output value in Q13
250e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kFactor1Table[257] = {
251e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192,
252e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
253e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
254e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
255e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
256e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8233, 8274, 8315, 8355, 8396, 8436, 8475, 8515, 8554, 8592, 8631, 8669,
257e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8707, 8745, 8783, 8820, 8857, 8894, 8931, 8967, 9003, 9039, 9075, 9111, 9146, 9181,
258e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        9216, 9251, 9286, 9320, 9354, 9388, 9422, 9456, 9489, 9523, 9556, 9589, 9622, 9655,
259e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        9687, 9719, 9752, 9784, 9816, 9848, 9879, 9911, 9942, 9973, 10004, 10035, 10066,
260e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        10097, 10128, 10158, 10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426,
261e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        10456, 10485, 10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770,
262e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        10798, 10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596,
263e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235, 10203,
264e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        10173, 10142, 10112, 10082, 10052, 10023, 9994, 9965, 9936, 9908, 9879, 9851, 9824,
265e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        9796, 9769, 9742, 9715, 9689, 9662, 9636, 9610, 9584, 9559, 9534, 9508, 9484, 9459,
266e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        9434, 9410, 9386, 9362, 9338, 9314, 9291, 9268, 9245, 9222, 9199, 9176, 9154, 9132,
267e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        9110, 9088, 9066, 9044, 9023, 9002, 8980, 8959, 8939, 8918, 8897, 8877, 8857, 8836,
268e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8816, 8796, 8777, 8757, 8738, 8718, 8699, 8680, 8661, 8642, 8623, 8605, 8586, 8568,
269e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8550, 8532, 8514, 8496, 8478, 8460, 8443, 8425, 8408, 8391, 8373, 8356, 8339, 8323,
270e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8306, 8289, 8273, 8256, 8240, 8224, 8208, 8192
271e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
272e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
273e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Gain factor table: Input value in Q8 and output value in Q13
274e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kFactor2Aggressiveness1[257] = {
275e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7577, 7577, 7577, 7577, 7577, 7577,
276e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632,
277e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
278e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
279e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
280e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
281e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
282e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
283e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
284e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
285e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
286e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
287e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
288e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
289e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
290e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
291e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
292e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
293e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
294e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
295e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
296e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Gain factor table: Input value in Q8 and output value in Q13
297e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kFactor2Aggressiveness2[257] = {
298e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7270, 7270, 7270, 7270, 7270, 7306,
299e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632,
300e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
301e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
302e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
303e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
304e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
305e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
306e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
307e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
308e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
309e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
310e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
311e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
312e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
313e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
314e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
315e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
316e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
317e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
318e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
319e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Gain factor table: Input value in Q8 and output value in Q13
320e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kFactor2Aggressiveness3[257] = {
321e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7184, 7184, 7184, 7229, 7270, 7306,
322e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632,
323e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
324e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
325e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
326e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
327e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
328e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
329e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
330e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
331e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
332e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
333e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
334e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
335e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
336e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
337e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
338e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
339e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
340e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
341e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
342e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// sum of log2(i) from table index to inst->anaLen2 in Q5
343e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Note that the first table value is invalid, since log2(0) = -infinity
344e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kSumLogIndex[66] = {
345e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        0,  22917,  22917,  22885,  22834,  22770,  22696,  22613,
346e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    22524,  22428,  22326,  22220,  22109,  21994,  21876,  21754,
347e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    21629,  21501,  21370,  21237,  21101,  20963,  20822,  20679,
348e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    20535,  20388,  20239,  20089,  19937,  19783,  19628,  19470,
349e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    19312,  19152,  18991,  18828,  18664,  18498,  18331,  18164,
350e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    17994,  17824,  17653,  17480,  17306,  17132,  16956,  16779,
351e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16602,  16423,  16243,  16063,  15881,  15699,  15515,  15331,
352e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    15146,  14960,  14774,  14586,  14398,  14209,  14019,  13829,
353e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    13637,  13445
354e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
355e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
356e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// sum of log2(i)^2 from table index to inst->anaLen2 in Q2
357e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Note that the first table value is invalid, since log2(0) = -infinity
358e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kSumSquareLogIndex[66] = {
359e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        0,  16959,  16959,  16955,  16945,  16929,  16908,  16881,
360e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16850,  16814,  16773,  16729,  16681,  16630,  16575,  16517,
361e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16456,  16392,  16325,  16256,  16184,  16109,  16032,  15952,
362e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    15870,  15786,  15700,  15612,  15521,  15429,  15334,  15238,
363e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    15140,  15040,  14938,  14834,  14729,  14622,  14514,  14404,
364e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    14292,  14179,  14064,  13947,  13830,  13710,  13590,  13468,
365e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    13344,  13220,  13094,  12966,  12837,  12707,  12576,  12444,
366e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    12310,  12175,  12039,  11902,  11763,  11624,  11483,  11341,
367e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    11198,  11054
368e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
369e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
370e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// log2(table index) in Q12
371e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Note that the first table value is invalid, since log2(0) = -infinity
372e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kLogIndex[129] = {
373e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        0,      0,   4096,   6492,   8192,   9511,  10588,  11499,
374e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    12288,  12984,  13607,  14170,  14684,  15157,  15595,  16003,
375e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    16384,  16742,  17080,  17400,  17703,  17991,  18266,  18529,
376e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    18780,  19021,  19253,  19476,  19691,  19898,  20099,  20292,
377e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    20480,  20662,  20838,  21010,  21176,  21338,  21496,  21649,
378e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    21799,  21945,  22087,  22226,  22362,  22495,  22625,  22752,
379e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    22876,  22998,  23117,  23234,  23349,  23462,  23572,  23680,
380e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    23787,  23892,  23994,  24095,  24195,  24292,  24388,  24483,
381e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    24576,  24668,  24758,  24847,  24934,  25021,  25106,  25189,
382e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    25272,  25354,  25434,  25513,  25592,  25669,  25745,  25820,
383e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    25895,  25968,  26041,  26112,  26183,  26253,  26322,  26390,
384e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    26458,  26525,  26591,  26656,  26721,  26784,  26848,  26910,
385e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    26972,  27033,  27094,  27154,  27213,  27272,  27330,  27388,
386e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    27445,  27502,  27558,  27613,  27668,  27722,  27776,  27830,
387e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    27883,  27935,  27988,  28039,  28090,  28141,  28191,  28241,
388e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    28291,  28340,  28388,  28437,  28484,  28532,  28579,  28626,
389e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    28672
390e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
391e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
392e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// determinant of estimation matrix in Q0 corresponding to the log2 tables above
393e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Note that the first table value is invalid, since log2(0) = -infinity
394e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentstatic const WebRtc_Word16 kDeterminantEstMatrix[66] = {
395e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        0,  29814,  25574,  22640,  20351,  18469,  16873,  15491,
396e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    14277,  13199,  12233,  11362,  10571,   9851,   9192,   8587,
397e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     8030,   7515,   7038,   6596,   6186,   5804,   5448,   5115,
398e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     4805,   4514,   4242,   3988,   3749,   3524,   3314,   3116,
399e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     2930,   2755,   2590,   2435,   2289,   2152,   2022,   1900,
400e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     1785,   1677,   1575,   1478,   1388,   1302,   1221,   1145,
401e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent     1073,   1005,    942,    881,    825,    771,    721,    674,
402e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent      629,    587,    547,    510,    475,    442,    411,    382,
403e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent      355,    330
404e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent};
405e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
406e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_UpdateNoiseEstimate(NsxInst_t *inst, int offset)
407e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
408e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no1 = 0;
409e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no2 = 0;
410e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
411e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 tmp16no1 = 0;
412e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 tmp16no2 = 0;
413e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 exp2Const = 11819; // Q13
414e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
415e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i = 0;
416e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
417e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp16no2 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset, inst->magnLen);
418e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->qNoise = 14
419e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            - (int)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(exp2Const, tmp16no2, 21);
420e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
421e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
422e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // inst->quantile[i]=exp(inst->lquantile[offset+i]);
423e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // in Q21
424e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no2 = WEBRTC_SPL_MUL_16_16(exp2Const, inst->noiseEstLogQuantile[offset + i]);
425e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF));
426e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 = -(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no2, 21);
427e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 += 21;// shift 21 to get result in Q0
428e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 -= (WebRtc_Word16)inst->qNoise; //shift to get result in Q(qNoise)
429e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmp16no1 > 0)
430e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
431e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->noiseEstQuantile[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1 +
432e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                       kRoundTable[tmp16no1], tmp16no1);
433e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
434e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        else
435e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
436e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->noiseEstQuantile[i] = (WebRtc_Word16)WEBRTC_SPL_LSHIFT_W32(tmp32no1,
437e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                             -tmp16no1);
438e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
439e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
440e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
441e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
442e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_CalcParametricNoiseEstimate(NsxInst_t *inst,
443e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                           WebRtc_Word16 pink_noise_exp_avg,
444e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                           WebRtc_Word32 pink_noise_num_avg,
445e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                           int freq_index,
446e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                           WebRtc_UWord32 *noise_estimate,
447e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                           WebRtc_UWord32 *noise_estimate_avg)
448e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
449e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no1 = 0;
450e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no2 = 0;
451e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
452e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 int_part = 0;
453e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 frac_part = 0;
454e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
455e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Use pink noise estimate
456e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j))
457e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    assert(freq_index > 0);
458e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no2 = WEBRTC_SPL_MUL_16_16(pink_noise_exp_avg, kLogIndex[freq_index]); // Q26
459e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 15); // Q11
460e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no1 = pink_noise_num_avg - tmp32no2; // Q11
461e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
462e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Calculate output: 2^tmp32no1
463e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Output in Q(minNorm-stages)
464e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no1 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)(inst->minNorm - inst->stages), 11);
465e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (tmp32no1 > 0)
466e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
467e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        int_part = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 11);
468e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        frac_part = (WebRtc_Word16)(tmp32no1 & 0x000007ff); // Q11
469e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Piecewise linear approximation of 'b' in
470e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // 2^(int_part+frac_part) = 2^int_part * (1 + b)
471e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // 'b' is given in Q11 and below stored in frac_part.
472e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (WEBRTC_SPL_RSHIFT_W32(frac_part, 10))
473e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
474e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Upper fractional part
475e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no2 = WEBRTC_SPL_MUL_32_16(2048 - frac_part, 1244); // Q21
476e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no2 = 2048 - WEBRTC_SPL_RSHIFT_W32(tmp32no2, 10);
477e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
478e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        else
479e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
480e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Lower fractional part
481e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no2 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(frac_part, 804), 10);
482e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
483e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Shift fractional part to Q(minNorm-stages)
484e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11);
485e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        *noise_estimate_avg = WEBRTC_SPL_LSHIFT_U32(1, int_part) + (WebRtc_UWord32)tmp32no2;
486e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Scale up to initMagnEst, which is not block averaged
487e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        *noise_estimate = (*noise_estimate_avg) * (WebRtc_UWord32)(inst->blockIndex + 1);
488e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
489e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
490e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
491e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Initialize state
492e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric LaurentWebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t *inst, WebRtc_UWord32 fs)
493e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
494e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i;
495e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
496e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //check for valid pointer
497e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst == NULL)
498e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
499e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return -1;
500e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
501e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //
502e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
503e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Initialization of struct
504e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (fs == 8000 || fs == 16000 || fs == 32000)
505e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
506e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->fs = fs;
507e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
508e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
509e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return -1;
510e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
511e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
512e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (fs == 8000)
513e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
514e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->blockLen10ms = 80;
515e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->anaLen = 128;
516e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->stages = 7;
517e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->window = kBlocks80w128x;
518e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->thresholdLogLrt = 131072; //default threshold for LRT feature
519e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->maxLrt = 0x0040000;
520e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->minLrt = 52429;
521e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else if (fs == 16000)
522e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
523e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->blockLen10ms = 160;
524e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->anaLen = 256;
525e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->stages = 8;
526e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->window = kBlocks160w256x;
527e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->thresholdLogLrt = 212644; //default threshold for LRT feature
528e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->maxLrt = 0x0080000;
529e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->minLrt = 104858;
530e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else if (fs == 32000)
531e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
532e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->blockLen10ms = 160;
533e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->anaLen = 256;
534e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->stages = 8;
535e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->window = kBlocks160w256x;
536e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->thresholdLogLrt = 212644; //default threshold for LRT feature
537e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->maxLrt = 0x0080000;
538e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->minLrt = 104858;
539e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
540e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->anaLen2 = WEBRTC_SPL_RSHIFT_W16(inst->anaLen, 1);
541e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->magnLen = inst->anaLen2 + 1;
542e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
543e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX);
544e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX);
545e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
546e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // for HB processing
547e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX, ANAL_BLOCKL_MAX);
548e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // for quantile noise estimation
549e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL);
550e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++)
551e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
552e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->noiseEstLogQuantile[i] = 2048; // Q8
553e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->noiseEstDensity[i] = 153; // Q9
554e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
555e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < SIMULT; i++)
556e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
557e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->noiseEstCounter[i] = (WebRtc_Word16)(END_STARTUP_LONG * (i + 1)) / SIMULT;
558e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
559e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
560e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Initialize suppression filter with ones
561e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_MemSetW16((WebRtc_Word16*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL);
562e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
563e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Set the aggressiveness: default
564e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->aggrMode = 0;
565e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
566e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //initialize variables for new method
567e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->priorNonSpeechProb = 8192; // Q14(0.5) prior probability for speech/noise
568e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < HALF_ANAL_BLOCKL; i++)
569e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
570e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->prevMagnU16[i] = 0;
571e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->prevNoiseU32[i] = 0; //previous noise-spectrum
572e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->logLrtTimeAvgW32[i] = 0; //smooth LR ratio
573e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->avgMagnPause[i] = 0; //conservative noise spectrum estimate
574e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->initMagnEst[i] = 0; //initial average magnitude spectrum
575e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
576e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
577e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //feature quantities
578e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->thresholdSpecDiff = 50; //threshold for difference feature: determined on-line
579e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->thresholdSpecFlat = 20480; //threshold for flatness: determined on-line
580e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->featureLogLrt = inst->thresholdLogLrt; //average LRT factor (= threshold)
581e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->featureSpecFlat = inst->thresholdSpecFlat; //spectral flatness (= threshold)
582e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->featureSpecDiff = inst->thresholdSpecDiff; //spectral difference (= threshold)
583e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->weightLogLrt = 6; //default weighting par for LRT feature
584e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->weightSpecFlat = 0; //default weighting par for spectral flatness feature
585e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->weightSpecDiff = 0; //default weighting par for spectral difference feature
586e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
587e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->curAvgMagnEnergy = 0; //window time-average of input magnitude spectrum
588e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->timeAvgMagnEnergy = 0; //normalization for spectral difference
589e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->timeAvgMagnEnergyTmp = 0; //normalization for spectral difference
590e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
591e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //histogram quantities: used to estimate/update thresholds for features
592e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
593e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
594e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
595e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
596e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->blockIndex = -1; //frame counter
597e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
598e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //inst->modelUpdate    = 500;   //window for update
599e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->modelUpdate = (1 << STAT_UPDATES); //window for update
600e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->cntThresUpdate = 0; //counter feature thresholds updates
601e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
602e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->sumMagn = 0;
603e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->magnEnergy = 0;
604e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->prevQMagn = 0;
605e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->qNoise = 0;
606e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->prevQNoise = 0;
607e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
608e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->energyIn = 0;
609e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->scaleEnergyIn = 0;
610e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
611e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->whiteNoiseLevel = 0;
612e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->pinkNoiseNumerator = 0;
613e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->pinkNoiseExp = 0;
614e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->minNorm = 15; // Start with full scale
615e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->zeroInputSignal = 0;
616e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
617e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //default mode
618e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_set_policy_core(inst, 0);
619e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
620e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#ifdef NS_FILEDEBUG
621e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->infile=fopen("indebug.pcm","wb");
622e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->outfile=fopen("outdebug.pcm","wb");
623e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->file1=fopen("file1.pcm","wb");
624e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->file2=fopen("file2.pcm","wb");
625e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->file3=fopen("file3.pcm","wb");
626e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->file4=fopen("file4.pcm","wb");
627e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->file5=fopen("file5.pcm","wb");
628e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#endif
629e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
630e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->initFlag = 1;
631e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
632e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    return 0;
633e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
634e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
635e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentint WebRtcNsx_set_policy_core(NsxInst_t *inst, int mode)
636e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
637e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // allow for modes:0,1,2,3
638e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (mode < 0 || mode > 3)
639e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
640e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return -1;
641e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
642e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
643e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->aggrMode = mode;
644e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (mode == 0)
645e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
646e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->overdrive = 256; // Q8(1.0)
647e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->denoiseBound = 8192; // Q14(0.5)
648e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->gainMap = 0; // No gain compensation
649e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else if (mode == 1)
650e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
651e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->overdrive = 256; // Q8(1.0)
652e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->denoiseBound = 4096; // Q14(0.25)
653e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->factor2Table = kFactor2Aggressiveness1;
654e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->gainMap = 1;
655e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else if (mode == 2)
656e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
657e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->overdrive = 282; // ~= Q8(1.1)
658e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->denoiseBound = 2048; // Q14(0.125)
659e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->factor2Table = kFactor2Aggressiveness2;
660e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->gainMap = 1;
661e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else if (mode == 3)
662e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
663e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->overdrive = 320; // Q8(1.25)
664e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->denoiseBound = 1475; // ~= Q14(0.09)
665e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->factor2Table = kFactor2Aggressiveness3;
666e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->gainMap = 1;
667e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
668e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    return 0;
669e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
670e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
671e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_NoiseEstimation(NsxInst_t *inst, WebRtc_UWord16 *magn, WebRtc_UWord32 *noise,
672e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                               WebRtc_Word16 *qNoise)
673e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
674e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 numerator;
675e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
676e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 lmagn[HALF_ANAL_BLOCKL], counter, countDiv, countProd, delta, zeros, frac;
677e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 log2, tabind, logval, tmp16, tmp16no1, tmp16no2;
678e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 log2Const = 22713; // Q15
679e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 widthFactor = 21845;
680e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
681e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i, s, offset;
682e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
683e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    numerator = FACTOR_Q16;
684e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
685e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tabind = inst->stages - inst->normData;
686e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (tabind < 0)
687e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
688e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        logval = -kLogTable[-tabind];
689e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
690e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
691e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        logval = kLogTable[tabind];
692e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
693e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
694e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // lmagn(i)=log(magn(i))=log(2)*log2(magn(i))
695e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // magn is in Q(-stages), and the real lmagn values are:
696e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages)
697e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // lmagn in Q8
698e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
699e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
700e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (magn[i])
701e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
702e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]);
703e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            frac = (WebRtc_Word16)((((WebRtc_UWord32)magn[i] << zeros) & 0x7FFFFFFF) >> 23);
704e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // log2(magn(i))
705e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            log2 = (WebRtc_Word16)(((31 - zeros) << 8) + kLogTableFrac[frac]);
706e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // log2(magn(i))*log(2)
707e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            lmagn[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2Const, 15);
708e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // + log(2^stages)
709e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            lmagn[i] += logval;
710e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
711e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
712e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            lmagn[i] = logval;//0;
713e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
714e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
715e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
716e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // loop over simultaneous estimates
717e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (s = 0; s < SIMULT; s++)
718e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
719e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        offset = s * inst->magnLen;
720e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
721e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Get counter values from state
722e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        counter = inst->noiseEstCounter[s];
723e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        countDiv = kCounterDiv[counter];
724e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        countProd = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(counter, countDiv);
725e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
726e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // quant_est(...)
727e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < inst->magnLen; i++)
728e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
729e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // compute delta
730e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (inst->noiseEstDensity[offset + i] > 512)
731e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
732e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                delta = WebRtcSpl_DivW32W16ResW16(numerator,
733e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                  inst->noiseEstDensity[offset + i]);
734e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
735e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
736e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                delta = FACTOR_Q7;
737e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
738e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
739e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // update log quantile estimate
740e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14);
741e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (lmagn[i] > inst->noiseEstLogQuantile[offset + i])
742e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
743e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2
744e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // CounterDiv=1/inst->counter[s] in Q15
745e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16 += 2;
746e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2);
747e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                inst->noiseEstLogQuantile[offset + i] += tmp16no1;
748e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
749e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
750e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16 += 1;
751e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1);
752e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2
753e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1);
754e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                inst->noiseEstLogQuantile[offset + i] -= tmp16no2;
755e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
756e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
757e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // update density estimate
758e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i])
759e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    < WIDTH_Q8)
760e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
761e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
762e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                        inst->noiseEstDensity[offset + i], countProd, 15);
763e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(widthFactor,
764e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                               countDiv, 15);
765e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2;
766e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
767e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } // end loop over magnitude spectrum
768e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
769e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (counter >= END_STARTUP_LONG)
770e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
771e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->noiseEstCounter[s] = 0;
772e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (inst->blockIndex >= END_STARTUP_LONG)
773e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
774e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                WebRtcNsx_UpdateNoiseEstimate(inst, offset);
775e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
776e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
777e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->noiseEstCounter[s]++;
778e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
779e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // end loop over simultaneous estimates
780e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
781e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Sequentially update the noise during startup
782e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->blockIndex < END_STARTUP_LONG)
783e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
784e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WebRtcNsx_UpdateNoiseEstimate(inst, offset);
785e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
786e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
787e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
788e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
789e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        noise[i] = (WebRtc_UWord32)(inst->noiseEstQuantile[i]); // Q(qNoise)
790e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
791e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    (*qNoise) = (WebRtc_Word16)inst->qNoise;
792e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
793e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
794e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Extract thresholds for feature parameters
795e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// histograms are computed over some window_size (given by window_pars)
796e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// thresholds and weights are extracted every window
797e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// flag 0 means update histogram only, flag 1 means compute the thresholds/weights
798e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// threshold and weights are returned in: inst->priorModelPars
799e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_FeatureParameterExtraction(NsxInst_t *inst, int flag)
800e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
801e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 tmpU32;
802e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 histIndex;
803e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 posPeak1SpecFlatFX, posPeak2SpecFlatFX;
804e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 posPeak1SpecDiffFX, posPeak2SpecDiffFX;
805e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
806e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32;
807e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 fluctLrtFX, thresFluctLrtFX;
808e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX;
809e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
810e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 j;
811e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 numHistLrt;
812e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
813e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i;
814e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int useFeatureSpecFlat, useFeatureSpecDiff, featureSum;
815e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int maxPeak1, maxPeak2;
816e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int weightPeak1SpecFlat, weightPeak2SpecFlat;
817e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int weightPeak1SpecDiff, weightPeak2SpecDiff;
818e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
819e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //update histograms
820e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (!flag)
821e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
822e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // LRT
823e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Type casting to UWord32 is safe since negative values will not be wrapped to larger
824e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // values than HIST_PAR_EST
825e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        histIndex = (WebRtc_UWord32)(inst->featureLogLrt);
826e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (histIndex < HIST_PAR_EST)
827e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
828e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->histLrt[histIndex]++;
829e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
830e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Spectral flatness
831e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8
832e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        histIndex = WEBRTC_SPL_RSHIFT_U32(inst->featureSpecFlat * 5, 8);
833e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (histIndex < HIST_PAR_EST)
834e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
835e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->histSpecFlat[histIndex]++;
836e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
837e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Spectral difference
838e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        histIndex = HIST_PAR_EST;
839e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->timeAvgMagnEnergy)
840e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
841e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Guard against division by zero
842e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // If timeAvgMagnEnergy == 0 we have no normalizing statistics and therefore can't
843e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // update the histogram
844e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            histIndex = WEBRTC_SPL_UDIV((inst->featureSpecDiff * 5) >> inst->stages,
845e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                        inst->timeAvgMagnEnergy);
846e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
847e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (histIndex < HIST_PAR_EST)
848e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
849e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->histSpecDiff[histIndex]++;
850e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
851e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
852e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
853e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // extract parameters for speech/noise probability
854e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (flag)
855e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
856e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        useFeatureSpecDiff = 1;
857e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //for LRT feature:
858e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // compute the average over inst->featureExtractionParams.rangeAvgHistLrt
859e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgHistLrtFX = 0;
860e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgSquareHistLrtFX = 0;
861e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        numHistLrt = 0;
862e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < BIN_SIZE_LRT; i++)
863e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
864e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            j = (2 * i + 1);
865e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j);
866e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            avgHistLrtFX += tmp32;
867e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            numHistLrt += inst->histLrt[i];
868e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j);
869e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
870e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgHistLrtComplFX = avgHistLrtFX;
871e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (; i < HIST_PAR_EST; i++)
872e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
873e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            j = (2 * i + 1);
874e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j);
875e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            avgHistLrtComplFX += tmp32;
876e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j);
877e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
878e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        fluctLrtFX = WEBRTC_SPL_MUL(avgSquareHistLrtFX, numHistLrt);
879e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        fluctLrtFX -= WEBRTC_SPL_MUL(avgHistLrtFX, avgHistLrtComplFX);
880e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt;
881e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // get threshold for LRT feature:
882e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32 = (FACTOR_1_LRT_DIFF * (WebRtc_UWord32)avgHistLrtFX);
883e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) || (tmpU32
884e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                > (WebRtc_UWord32)(100 * numHistLrt)))
885e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
886e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->thresholdLogLrt = inst->maxLrt; //very low fluctuation, so likely noise
887e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
888e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
889e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32 = (WebRtc_Word32)((tmpU32 << (9 + inst->stages)) / numHistLrt / 25);
890e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // check if value is within min/max range
891e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt, tmp32, inst->minLrt);
892e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
893e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (fluctLrtFX < thresFluctLrtFX)
894e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
895e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Do not use difference feature if fluctuation of LRT feature is very low:
896e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // most likely just noise state
897e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            useFeatureSpecDiff = 0;
898e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
899e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
900e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // for spectral flatness and spectral difference: compute the main peaks of histogram
901e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        maxPeak1 = 0;
902e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        maxPeak2 = 0;
903e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        posPeak1SpecFlatFX = 0;
904e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        posPeak2SpecFlatFX = 0;
905e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        weightPeak1SpecFlat = 0;
906e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        weightPeak2SpecFlat = 0;
907e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
908e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // peaks for flatness
909e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < HIST_PAR_EST; i++)
910e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
911e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (inst->histSpecFlat[i] > maxPeak1)
912e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
913e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Found new "first" peak
914e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                maxPeak2 = maxPeak1;
915e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                weightPeak2SpecFlat = weightPeak1SpecFlat;
916e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                posPeak2SpecFlatFX = posPeak1SpecFlatFX;
917e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
918e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                maxPeak1 = inst->histSpecFlat[i];
919e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                weightPeak1SpecFlat = inst->histSpecFlat[i];
920e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                posPeak1SpecFlatFX = (WebRtc_UWord32)(2 * i + 1);
921e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else if (inst->histSpecFlat[i] > maxPeak2)
922e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
923e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Found new "second" peak
924e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                maxPeak2 = inst->histSpecFlat[i];
925e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                weightPeak2SpecFlat = inst->histSpecFlat[i];
926e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                posPeak2SpecFlatFX = (WebRtc_UWord32)(2 * i + 1);
927e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
928e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
929e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
930e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // for spectral flatness feature
931e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        useFeatureSpecFlat = 1;
932e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // merge the two peaks if they are close
933e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF)
934e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                && (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecFlat))
935e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
936e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            weightPeak1SpecFlat += weightPeak2SpecFlat;
937e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1;
938e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
939e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //reject if weight of peaks is not large enough, or peak value too small
940e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF || posPeak1SpecFlatFX
941e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                < THRES_PEAK_FLAT)
942e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
943e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            useFeatureSpecFlat = 0;
944e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else // if selected, get the threshold
945e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
946e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // compute the threshold and check if value is within min/max range
947e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->thresholdSpecFlat = WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10
948e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                     * posPeak1SpecFlatFX, MIN_FLAT_Q10); //Q10
949e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
950e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // done with flatness feature
951e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
952e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (useFeatureSpecDiff)
953e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
954e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            //compute two peaks for spectral difference
955e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            maxPeak1 = 0;
956e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            maxPeak2 = 0;
957e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            posPeak1SpecDiffFX = 0;
958e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            posPeak2SpecDiffFX = 0;
959e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            weightPeak1SpecDiff = 0;
960e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            weightPeak2SpecDiff = 0;
961e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // peaks for spectral difference
962e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            for (i = 0; i < HIST_PAR_EST; i++)
963e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
964e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                if (inst->histSpecDiff[i] > maxPeak1)
965e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                {
966e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // Found new "first" peak
967e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    maxPeak2 = maxPeak1;
968e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    weightPeak2SpecDiff = weightPeak1SpecDiff;
969e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    posPeak2SpecDiffFX = posPeak1SpecDiffFX;
970e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
971e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    maxPeak1 = inst->histSpecDiff[i];
972e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    weightPeak1SpecDiff = inst->histSpecDiff[i];
973e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    posPeak1SpecDiffFX = (WebRtc_UWord32)(2 * i + 1);
974e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                } else if (inst->histSpecDiff[i] > maxPeak2)
975e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                {
976e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // Found new "second" peak
977e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    maxPeak2 = inst->histSpecDiff[i];
978e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    weightPeak2SpecDiff = inst->histSpecDiff[i];
979e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    posPeak2SpecDiffFX = (WebRtc_UWord32)(2 * i + 1);
980e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                }
981e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
982e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
983e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // merge the two peaks if they are close
984e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX < LIM_PEAK_SPACE_FLAT_DIFF)
985e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    && (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecDiff))
986e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
987e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                weightPeak1SpecDiff += weightPeak2SpecDiff;
988e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1;
989e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
990e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // get the threshold value and check if value is within min/max range
991e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->thresholdSpecDiff = WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF
992e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                     * posPeak1SpecDiffFX, MIN_DIFF); //5x bigger
993e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            //reject if weight of peaks is not large enough
994e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF)
995e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
996e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                useFeatureSpecDiff = 0;
997e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
998e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // done with spectral difference feature
999e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1000e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1001e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // select the weights between the features
1002e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // inst->priorModelPars[4] is weight for LRT: always selected
1003e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff);
1004e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->weightLogLrt = featureSum;
1005e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->weightSpecFlat = useFeatureSpecFlat * featureSum;
1006e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->weightSpecDiff = useFeatureSpecDiff * featureSum;
1007e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1008e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // set histograms to zero for next update
1009e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
1010e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
1011e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
1012e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // end of flag == 1
1013e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
1014e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1015e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1016e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Compute spectral flatness on input spectrum
1017e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// magn is the magnitude spectrum
1018e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// spectral flatness is returned in inst->featureSpecFlat
1019e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_ComputeSpectralFlatness(NsxInst_t *inst, WebRtc_UWord16 *magn)
1020e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
1021e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 tmpU32;
1022e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 avgSpectralFlatnessNum, avgSpectralFlatnessDen;
1023e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1024e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32;
1025e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 currentSpectralFlatness, logCurSpectralFlatness;
1026e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1027e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 zeros, frac, intPart;
1028e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1029e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i;
1030e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1031e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // for flatness
1032e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    avgSpectralFlatnessNum = 0;
1033e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    avgSpectralFlatnessDen = inst->sumMagn - (WebRtc_UWord32)magn[0]; // Q(normData-stages)
1034e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1035e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // compute log of ratio of the geometric to arithmetic mean: check for log(0) case
1036e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) )
1037e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //          = exp( sum(log(magn[i]))/N ) * N / sum(magn[i])
1038e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //          = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) ) [This is used]
1039e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 1; i < inst->magnLen; i++)
1040e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1041e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // First bin is excluded from spectrum measures. Number of bins is now a power of 2
1042e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (magn[i])
1043e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1044e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]);
1045e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            frac = (WebRtc_Word16)(((WebRtc_UWord32)((WebRtc_UWord32)(magn[i]) << zeros)
1046e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    & 0x7FFFFFFF) >> 23);
1047e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // log2(magn(i))
1048e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32 = (WebRtc_UWord32)(((31 - zeros) << 8) + kLogTableFrac[frac]); // Q8
1049e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            avgSpectralFlatnessNum += tmpU32; // Q8
1050e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
1051e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1052e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            //if at least one frequency component is zero, treat separately
1053e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat, SPECT_FLAT_TAVG_Q14); // Q24
1054e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->featureSpecFlat -= WEBRTC_SPL_RSHIFT_U32(tmpU32, 14); // Q10
1055e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            return;
1056e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1057e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1058e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //ratio and inverse log: check for case of log(0)
1059e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen);
1060e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    frac = (WebRtc_Word16)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23);
1061e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // log2(avgSpectralFlatnessDen)
1062e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32 = (WebRtc_Word32)(((31 - zeros) << 8) + kLogTableFrac[frac]); // Q8
1063e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    logCurSpectralFlatness = (WebRtc_Word32)avgSpectralFlatnessNum;
1064e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    logCurSpectralFlatness += ((WebRtc_Word32)(inst->stages - 1) << (inst->stages + 7)); // Q(8+stages-1)
1065e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    logCurSpectralFlatness -= (tmp32 << (inst->stages - 1));
1066e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    logCurSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(logCurSpectralFlatness, 10 - inst->stages); // Q17
1067e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32 = (WebRtc_Word32)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness)
1068e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            & 0x0001FFFF)); //Q17
1069e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    intPart = -(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(logCurSpectralFlatness, 17);
1070e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    intPart += 7; // Shift 7 to get the output in Q10 (from Q17 = -17+10)
1071e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (intPart > 0)
1072e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1073e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        currentSpectralFlatness = WEBRTC_SPL_RSHIFT_W32(tmp32, intPart);
1074e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
1075e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1076e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        currentSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(tmp32, -intPart);
1077e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1078e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1079e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //time average update of spectral flatness feature
1080e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32 = currentSpectralFlatness - (WebRtc_Word32)inst->featureSpecFlat; // Q10
1081e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32 = WEBRTC_SPL_MUL_32_16(SPECT_FLAT_TAVG_Q14, tmp32); // Q24
1082e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->featureSpecFlat = (WebRtc_UWord32)((WebRtc_Word32)inst->featureSpecFlat
1083e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            + WEBRTC_SPL_RSHIFT_W32(tmp32, 14)); // Q10
1084e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // done with flatness feature
1085e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
1086e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1087e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1088e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Compute the difference measure between input spectrum and a template/learned noise spectrum
1089e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// magn_tmp is the input spectrum
1090e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// the reference/template spectrum is  inst->magn_avg_pause[i]
1091e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// returns (normalized) spectral difference in inst->featureSpecDiff
1092e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_ComputeSpectralDifference(NsxInst_t *inst, WebRtc_UWord16 *magnIn)
1093e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
1094e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // This is to be calculated:
1095e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause)
1096e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1097e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 tmpU32no1, tmpU32no2;
1098e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 varMagnUFX, varPauseUFX, avgDiffNormMagnUFX;
1099e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1100e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no1, tmp32no2;
1101e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 avgPauseFX, avgMagnFX, covMagnPauseFX;
1102e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 maxPause, minPause;
1103e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1104e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 tmp16no1;
1105e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1106e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i, norm32, nShifts;
1107e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1108e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    avgPauseFX = 0;
1109e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    maxPause = 0;
1110e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    minPause = inst->avgMagnPause[0]; // Q(prevQMagn)
1111e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // compute average quantities
1112e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
1113e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1114e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Compute mean of magn_pause
1115e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgPauseFX += inst->avgMagnPause[i]; // in Q(prevQMagn)
1116e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]);
1117e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]);
1118e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1119e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts
1120e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    avgPauseFX = WEBRTC_SPL_RSHIFT_W32(avgPauseFX, inst->stages - 1);
1121e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    avgMagnFX = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(inst->sumMagn, inst->stages - 1);
1122e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Largest possible deviation in magnPause for (co)var calculations
1123e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause);
1124e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Get number of shifts to make sure we don't get wrap around in varPause
1125e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1));
1126e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1127e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    varMagnUFX = 0;
1128e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    varPauseUFX = 0;
1129e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    covMagnPauseFX = 0;
1130e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
1131e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1132e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Compute var and cov of magn and magn_pause
1133e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 = (WebRtc_Word16)((WebRtc_Word32)magnIn[i] - avgMagnFX);
1134e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no2 = inst->avgMagnPause[i] - avgPauseFX;
1135e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        varMagnUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1); // Q(2*qMagn)
1136e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16no1); // Q(prevQMagn+qMagn)
1137e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        covMagnPauseFX += tmp32no1; // Q(prevQMagn+qMagn)
1138e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, nShifts); // Q(prevQMagn-minPause)
1139e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        varPauseUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL(tmp32no1, tmp32no1); // Q(2*(prevQMagn-minPause))
1140e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1141e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //update of average magnitude spectrum: Q(-2*stages) and averaging replaced by shifts
1142e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->curAvgMagnEnergy += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, 2 * inst->normData
1143e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                    + inst->stages - 1);
1144e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1145e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    avgDiffNormMagnUFX = varMagnUFX; // Q(2*qMagn)
1146e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if ((varPauseUFX) && (covMagnPauseFX))
1147e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1148e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(covMagnPauseFX); // Q(prevQMagn+qMagn)
1149e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16;
1150e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (norm32 > 0)
1151e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1152e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32); // Q(prevQMagn+qMagn+norm32)
1153e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
1154e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1155e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, -norm32); // Q(prevQMagn+qMagn+norm32)
1156e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1157e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1); // Q(2*(prevQMagn+qMagn-norm32))
1158e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1159e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nShifts += norm32;
1160e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nShifts <<= 1;
1161e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (nShifts < 0)
1162e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1163e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            varPauseUFX >>= (-nShifts); // Q(2*(qMagn+norm32+minPause))
1164e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            nShifts = 0;
1165e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1166e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no2, varPauseUFX); // Q(2*(qMagn+norm32-16+minPause))
1167e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, nShifts);
1168e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1169e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1); // Q(2*qMagn)
1170e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1171e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //normalize and compute time average update of difference feature
1172e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(avgDiffNormMagnUFX, 2 * inst->normData);
1173e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->featureSpecDiff > tmpU32no1)
1174e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1175e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1,
1176e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                          SPECT_DIFF_TAVG_Q8); // Q(8-2*stages)
1177e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->featureSpecDiff -= WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages)
1178e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
1179e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1180e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff,
1181e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                          SPECT_DIFF_TAVG_Q8); // Q(8-2*stages)
1182e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->featureSpecDiff += WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages)
1183e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1184e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
1185e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1186e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Compute speech/noise probability
1187e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// speech/noise probability is returned in: probSpeechFinal
1188e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent//snrLocPrior is the prior SNR for each frequency (in Q11)
1189e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent//snrLocPost is the post SNR for each frequency (in Q11)
1190e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_SpeechNoiseProb(NsxInst_t *inst, WebRtc_UWord16 *nonSpeechProbFinal,
1191e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                               WebRtc_UWord32 *priorLocSnr, WebRtc_UWord32 *postLocSnr)
1192e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
1193e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3;
1194e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1195e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32;
1196e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 frac32, logTmp;
1197e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 logLrtTimeAvgKsumFX;
1198e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1199e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 indPriorFX16;
1200e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart;
1201e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1202e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i, normTmp, normTmp2, nShifts;
1203e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1204e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // compute feature based on average LR factor
1205e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // this is the average over all frequencies of the smooth log LRT
1206e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    logLrtTimeAvgKsumFX = 0;
1207e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
1208e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1209e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        besselTmpFX32 = (WebRtc_Word32)postLocSnr[i]; // Q11
1210e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        normTmp = WebRtcSpl_NormU32(postLocSnr[i]);
1211e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        num = WEBRTC_SPL_LSHIFT_U32(postLocSnr[i], normTmp); // Q(11+normTmp)
1212e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (normTmp > 10)
1213e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1214e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            den = WEBRTC_SPL_LSHIFT_U32(priorLocSnr[i], normTmp - 11); // Q(normTmp)
1215e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
1216e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1217e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            den = WEBRTC_SPL_RSHIFT_U32(priorLocSnr[i], 11 - normTmp); // Q(normTmp)
1218e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1219e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        besselTmpFX32 -= WEBRTC_SPL_UDIV(num, den); // Q11
1220e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1221e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior) - inst->logLrtTimeAvg[i]);
1222e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Here, LRT_TAVG = 0.5
1223e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        zeros = WebRtcSpl_NormU32(priorLocSnr[i]);
1224e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        frac32 = (WebRtc_Word32)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19);
1225e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32 = WEBRTC_SPL_MUL(frac32, frac32);
1226e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(tmp32, -43), 19);
1227e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32 += WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)frac32, 5412, 12);
1228e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        frac32 = tmp32 + 37;
1229e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // tmp32 = log2(priorLocSnr[i])
1230e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32 = (WebRtc_Word32)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12
1231e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        logTmp = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32, 178), 8); // log2(priorLocSnr[i])*log(2)
1232e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = WEBRTC_SPL_RSHIFT_W32(logTmp + inst->logLrtTimeAvgW32[i], 1); // Q12
1233e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12
1234e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1235e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12
1236e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1237e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->featureLogLrt = WEBRTC_SPL_RSHIFT_W32(logLrtTimeAvgKsumFX * 5, inst->stages + 10); // 5 = BIN_SIZE_LRT / 2
1238e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // done with computation of LR factor
1239e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1240e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //
1241e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute the indicator functions
1242e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //
1243e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1244e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // average LRT feature
1245e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // FLOAT code
1246e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // indicator0 = 0.5 * (tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.0);
1247e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpIndFX = 16384; // Q14(1.0)
1248e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12
1249e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5;
1250e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //use larger width in tanh map for pause regions
1251e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (tmp32no1 < 0)
1252e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1253e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpIndFX = 0;
1254e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = -tmp32no1;
1255e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //widthPrior = widthPrior * 2.0;
1256e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nShifts++;
1257e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1258e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14
1259e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // compute indicator function: sigmoid map
1260e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 14);
1261e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if ((tableIndex < 16) && (tableIndex >= 0))
1262e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1263e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no2 = kIndicatorTable[tableIndex];
1264e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
1265e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        frac = (WebRtc_Word16)(tmp32no1 & 0x00003fff); // Q14
1266e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14);
1267e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmpIndFX == 0)
1268e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1269e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpIndFX = 8192 - tmp16no2; // Q14
1270e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
1271e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1272e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpIndFX = 8192 + tmp16no2; // Q14
1273e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1274e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1275e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    indPriorFX = WEBRTC_SPL_MUL_16_16(inst->weightLogLrt, tmpIndFX); // 6*Q14
1276e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1277e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //spectral flatness feature
1278e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->weightSpecFlat)
1279e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1280e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10
1281e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpIndFX = 16384; // Q14(1.0)
1282e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //use larger width in tanh map for pause regions
1283e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10
1284e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nShifts = 4;
1285e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->thresholdSpecFlat < tmpU32no1)
1286e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1287e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpIndFX = 0;
1288e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat;
1289e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            //widthPrior = widthPrior * 2.0;
1290e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            nShifts++;
1291e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1292e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = (WebRtc_Word32)WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2,
1293e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                            nShifts), 25); //Q14
1294e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14
1295e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // compute indicator function: sigmoid map
1296e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // FLOAT code
1297e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // indicator1 = 0.5 * (tanh(sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) + 1.0);
1298e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14);
1299e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tableIndex < 16)
1300e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1301e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16no2 = kIndicatorTable[tableIndex];
1302e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
1303e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14
1304e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14);
1305e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (tmpIndFX)
1306e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1307e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpIndFX = 8192 + tmp16no2; // Q14
1308e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
1309e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1310e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpIndFX = 8192 - tmp16no2; // Q14
1311e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1312e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1313e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecFlat, tmpIndFX); // 6*Q14
1314e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1315e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1316e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //for template spectral-difference
1317e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->weightSpecDiff)
1318e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1319e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = 0;
1320e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->featureSpecDiff)
1321e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1322e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            normTmp = WEBRTC_SPL_MIN(20 - inst->stages,
1323e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                     WebRtcSpl_NormU32(inst->featureSpecDiff));
1324e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(inst->featureSpecDiff, normTmp); // Q(normTmp-2*stages)
1325e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->timeAvgMagnEnergy, 20 - inst->stages
1326e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                              - normTmp);
1327e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (tmpU32no2)
1328e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1329e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q14?? Q(20 - inst->stages)
1330e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
1331e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1332e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = (WebRtc_UWord32)(0x7fffffff);
1333e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1334e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1335e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no3 = WEBRTC_SPL_UDIV(WEBRTC_SPL_LSHIFT_U32(inst->thresholdSpecDiff, 17), 25);
1336e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = tmpU32no1 - tmpU32no3;
1337e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nShifts = 1;
1338e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpIndFX = 16384; // Q14(1.0)
1339e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //use larger width in tanh map for pause regions
1340e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmpU32no2 & 0x80000000)
1341e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1342e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpIndFX = 0;
1343e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = tmpU32no3 - tmpU32no1;
1344e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            //widthPrior = widthPrior * 2.0;
1345e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            nShifts--;
1346e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1347e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, nShifts);
1348e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // compute indicator function: sigmoid map
1349e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        /* FLOAT code
1350e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent         indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0);
1351e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent         */
1352e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14);
1353e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tableIndex < 16)
1354e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1355e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16no2 = kIndicatorTable[tableIndex];
1356e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
1357e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14
1358e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16no1, frac,
1359e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                            14);
1360e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (tmpIndFX)
1361e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1362e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpIndFX = 8192 + tmp16no2;
1363e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
1364e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1365e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpIndFX = 8192 - tmp16no2;
1366e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1367e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1368e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecDiff, tmpIndFX); // 6*Q14
1369e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1370e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1371e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //combine the indicator function with the feature weights
1372e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // FLOAT code
1373e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 * indicator2);
1374e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14
1375e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // done with computing indicator function
1376e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1377e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute the prior probability
1378e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // FLOAT code
1379e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // inst->priorNonSpeechProb += PRIOR_UPDATE * (indPriorNonSpeech - inst->priorNonSpeechProb);
1380e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14
1381e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->priorNonSpeechProb += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(PRIOR_UPDATE_Q14,
1382e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                         tmp16, 14); // Q14
1383e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1384e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //final speech probability: combine prior model with LR factor:
1385e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
1386e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1387e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // FLOAT code
1388e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // invLrt = exp(inst->logLrtTimeAvg[i]);
1389e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // invLrt = inst->priorSpeechProb * invLrt;
1390e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) / (1.0 - inst->priorSpeechProb + invLrt);
1391e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt;
1392e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // nonSpeechProbFinal[i] = inst->priorNonSpeechProb / (inst->priorNonSpeechProb + invLrt);
1393e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nonSpeechProbFinal[i] = 0; // Q8
1394e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if ((inst->logLrtTimeAvgW32[i] < 65300) && (inst->priorNonSpeechProb > 0))
1395e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1396e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no1 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(inst->logLrtTimeAvgW32[i], 23637),
1397e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                             14); // Q12
1398e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 12);
1399e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (intPart < -8)
1400e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1401e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                intPart = -8;
1402e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1403e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            frac = (WebRtc_Word16)(tmp32no1 & 0x00000fff); // Q12
1404e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Quadratic approximation of 2^frac
1405e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no2 = WEBRTC_SPL_RSHIFT_W32(frac * frac * 44, 19); // Q12
1406e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no2 += WEBRTC_SPL_MUL_16_16_RSFT(frac, 84, 7); // Q12
1407e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            invLrtFX = WEBRTC_SPL_LSHIFT_W32(1, 8 + intPart)
1408e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    + WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8
1409e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1410e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            normTmp = WebRtcSpl_NormW32(invLrtFX);
1411e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb));
1412e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (normTmp + normTmp2 < 15)
1413e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1414e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                invLrtFX = WEBRTC_SPL_RSHIFT_W32(invLrtFX, 15 - normTmp2 - normTmp); // Q(normTmp+normTmp2-7)
1415e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q(normTmp+normTmp2+7)
1416e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2); // Q14
1417e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
1418e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1419e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q22
1420e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                invLrtFX = WEBRTC_SPL_RSHIFT_W32(tmp32no1, 8); // Q14
1421e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1422e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1423e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inst->priorNonSpeechProb, 8); // Q22
1424e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            nonSpeechProbFinal[i] = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32no1,
1425e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    (WebRtc_Word32)inst->priorNonSpeechProb
1426e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    + invLrtFX); // Q8
1427e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (7 - normTmp - normTmp2 > 0)
1428e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1429e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                nonSpeechProbFinal[i] = 0; // Q8
1430e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1431e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1432e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1433e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
1434e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1435e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent// Transform input (speechFrame) to frequency domain magnitude (magnU16)
1436e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_DataAnalysis(NsxInst_t *inst, short *speechFrame, WebRtc_UWord16 *magnU16)
1437e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
1438e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1439e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 tmpU32no1, tmpU32no2;
1440e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1441e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32   tmp_1_w32 = 0;
1442e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32   tmp_2_w32 = 0;
1443e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32   sum_log_magn = 0;
1444e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32   sum_log_i_log_magn = 0;
1445e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1446e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16  sum_log_magn_u16 = 0;
1447e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16  tmp_u16 = 0;
1448e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1449e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   sum_log_i = 0;
1450e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   sum_log_i_square = 0;
1451e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   frac = 0;
1452e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   log2 = 0;
1453e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   matrix_determinant = 0;
1454e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   winData[ANAL_BLOCKL_MAX], maxWinData;
1455e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16   realImag[ANAL_BLOCKL_MAX << 1];
1456e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1457e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i, j;
1458e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int outCFFT;
1459e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int zeros;
1460e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int net_norm = 0;
1461e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int right_shifts_in_magnU16 = 0;
1462e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int right_shifts_in_initMagnEst = 0;
1463e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1464e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // For lower band do all processing
1465e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // update analysis buffer for L band
1466e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
1467e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                          inst->anaLen - inst->blockLen10ms);
1468e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms,
1469e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                          speechFrame, inst->blockLen10ms);
1470e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1471e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Window data before FFT
1472e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->anaLen; i++)
1473e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1474e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        winData[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(inst->window[i],
1475e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                inst->analysisBuffer[i],
1476e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                14); // Q0
1477e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1478e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Get input energy
1479e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->energyIn = WebRtcSpl_Energy(winData, (int)inst->anaLen, &(inst->scaleEnergyIn));
1480e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1481e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Reset zero input flag
1482e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->zeroInputSignal = 0;
1483e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Acquire norm for winData
1484e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen);
1485e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->normData = WebRtcSpl_NormW16(maxWinData);
1486e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (maxWinData == 0)
1487e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1488e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Treat zero input separately.
1489e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->zeroInputSignal = 1;
1490e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return;
1491e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1492e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1493e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Determine the net normalization in the frequency domain
1494e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    net_norm = inst->stages - inst->normData;
1495e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Track lowest normalization factor and use it to prevent wrap around in shifting
1496e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    right_shifts_in_magnU16 = inst->normData - inst->minNorm;
1497e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0);
1498e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->minNorm -= right_shifts_in_initMagnEst;
1499e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0);
1500e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1501e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // create realImag as winData interleaved with zeros (= imag. part), normalize it
1502e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->anaLen; i++)
1503e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1504e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        j = WEBRTC_SPL_LSHIFT_W16(i, 1);
1505e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        realImag[j] = WEBRTC_SPL_LSHIFT_W16(winData[i], inst->normData); // Q(normData)
1506e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        realImag[j + 1] = 0; // Insert zeros in imaginary part
1507e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1508e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1509e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // bit-reverse position of elements in array and FFT the array
1510e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ComplexBitReverse(realImag, inst->stages); // Q(normData-stages)
1511e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    outCFFT = WebRtcSpl_ComplexFFT(realImag, inst->stages, 1);
1512e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1513e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->imag[0] = 0; // Q(normData-stages)
1514e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->imag[inst->anaLen2] = 0;
1515e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->real[0] = realImag[0]; // Q(normData-stages)
1516e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->real[inst->anaLen2] = realImag[inst->anaLen];
1517e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Q(2*(normData-stages))
1518e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->magnEnergy = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[0], inst->real[0]);
1519e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->magnEnergy += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[inst->anaLen2],
1520e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                             inst->real[inst->anaLen2]);
1521e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    magnU16[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[0]); // Q(normData-stages)
1522e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    magnU16[inst->anaLen2] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]);
1523e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->sumMagn = (WebRtc_UWord32)magnU16[0]; // Q(normData-stages)
1524e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->sumMagn += (WebRtc_UWord32)magnU16[inst->anaLen2];
1525e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1526e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Gather information during startup for noise parameter estimation
1527e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->blockIndex < END_STARTUP_SHORT)
1528e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1529e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Switch initMagnEst to Q(minNorm-stages)
1530e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->initMagnEst[0] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[0],
1531e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                     right_shifts_in_initMagnEst);
1532e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->initMagnEst[inst->anaLen2] =
1533e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[inst->anaLen2],
1534e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                      right_shifts_in_initMagnEst); // Q(minNorm-stages)
1535e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1536e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Shift magnU16 to same domain as initMagnEst
1537e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[0],
1538e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                          right_shifts_in_magnU16); // Q(minNorm-stages)
1539e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[inst->anaLen2],
1540e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                          right_shifts_in_magnU16); // Q(minNorm-stages)
1541e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1542e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Update initMagnEst
1543e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->initMagnEst[0] += tmpU32no1; // Q(minNorm-stages)
1544e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->initMagnEst[inst->anaLen2] += tmpU32no2; // Q(minNorm-stages)
1545e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1546e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        log2 = 0;
1547e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (magnU16[inst->anaLen2])
1548e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1549e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Calculate log2(magnU16[inst->anaLen2])
1550e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[inst->anaLen2]);
1551e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[inst->anaLen2] << zeros) &
1552e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    0x7FFFFFFF) >> 23); // Q8
1553e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // log2(magnU16(i)) in Q8
1554e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            log2 = (WebRtc_Word16)(((31 - zeros) << 8) + kLogTableFrac[frac]);
1555e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1556e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1557e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        sum_log_magn = (WebRtc_Word32)log2; // Q8
1558e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // sum_log_i_log_magn in Q17
1559e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        sum_log_i_log_magn = (WEBRTC_SPL_MUL_16_16(kLogIndex[inst->anaLen2], log2) >> 3);
1560e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1561e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1562e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 1; i < inst->anaLen2; i++)
1563e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1564e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        j = WEBRTC_SPL_LSHIFT_W16(i, 1);
1565e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->real[i] = realImag[j];
1566e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->imag[i] = -realImag[j + 1];
1567e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // magnitude spectrum
1568e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // energy in Q(2*(normData-stages))
1569e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j], realImag[j]);
1570e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j + 1], realImag[j + 1]);
1571e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages))
1572e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1573e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        magnU16[i] = (WebRtc_UWord16)WebRtcSpl_Sqrt(tmpU32no1); // Q(normData-stages)
1574e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->sumMagn += (WebRtc_UWord32)magnU16[i]; // Q(normData-stages)
1575e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->blockIndex < END_STARTUP_SHORT)
1576e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1577e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Switch initMagnEst to Q(minNorm-stages)
1578e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->initMagnEst[i] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i],
1579e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                         right_shifts_in_initMagnEst);
1580e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1581e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Shift magnU16 to same domain as initMagnEst, i.e., Q(minNorm-stages)
1582e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[i],
1583e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                              right_shifts_in_magnU16);
1584e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Update initMagnEst
1585e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->initMagnEst[i] += tmpU32no1; // Q(minNorm-stages)
1586e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1587e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (i >= kStartBand)
1588e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1589e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // For pink noise estimation. Collect data neglecting lower frequency band
1590e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                log2 = 0;
1591e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                if (magnU16[i])
1592e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                {
1593e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[i]);
1594e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[i] << zeros) &
1595e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                            0x7FFFFFFF) >> 23);
1596e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // log2(magnU16(i)) in Q8
1597e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    log2 = (WebRtc_Word16)(((31 - zeros) << 8) + kLogTableFrac[frac]);
1598e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                }
1599e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                sum_log_magn += (WebRtc_Word32)log2; // Q8
1600e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // sum_log_i_log_magn in Q17
1601e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                sum_log_i_log_magn += (WEBRTC_SPL_MUL_16_16(kLogIndex[i], log2) >> 3);
1602e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1603e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1604e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1605e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1606e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute simplified noise model during startup
1607e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->blockIndex < END_STARTUP_SHORT)
1608e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1609e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Estimate White noise
1610e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Switch whiteNoiseLevel to Q(minNorm-stages)
1611e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->whiteNoiseLevel = WEBRTC_SPL_RSHIFT_U32(inst->whiteNoiseLevel,
1612e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      right_shifts_in_initMagnEst);
1613e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1614e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Update the average magnitude spectrum, used as noise estimate.
1615e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive);
1616e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages + 8);
1617e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1618e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Replacing division above with 'stages' shifts
1619e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Shift to same Q-domain as whiteNoiseLevel
1620e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, right_shifts_in_magnU16);
1621e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // This operation is safe from wrap around as long as END_STARTUP_SHORT < 128
1622e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        assert(END_STARTUP_SHORT < 128);
1623e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->whiteNoiseLevel += tmpU32no1; // Q(minNorm-stages)
1624e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1625e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Estimate Pink noise parameters
1626e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Denominator used in both parameter estimates.
1627e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // The value is only dependent on the size of the frequency band (kStartBand)
1628e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // and to reduce computational complexity stored in a table (kDeterminantEstMatrix[])
1629e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        matrix_determinant = kDeterminantEstMatrix[kStartBand]; // Q0
1630e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        sum_log_i = kSumLogIndex[kStartBand]; // Q5
1631e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        sum_log_i_square = kSumSquareLogIndex[kStartBand]; // Q2
1632e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->fs == 8000)
1633e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1634e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Adjust values to shorter blocks in narrow band.
1635e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_1_w32 = (WebRtc_Word32)matrix_determinant;
1636e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_1_w32 += WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], sum_log_i, 9);
1637e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], kSumLogIndex[65], 10);
1638e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_1_w32 -= WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)sum_log_i_square, 4);
1639e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)(inst->magnLen
1640e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    - kStartBand), kSumSquareLogIndex[65], 2);
1641e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            matrix_determinant = (WebRtc_Word16)tmp_1_w32;
1642e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            sum_log_i -= kSumLogIndex[65]; // Q5
1643e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            sum_log_i_square -= kSumSquareLogIndex[65]; // Q2
1644e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1645e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1646e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Necessary number of shifts to fit sum_log_magn in a word16
1647e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        zeros = 16 - WebRtcSpl_NormW32(sum_log_magn);
1648e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (zeros < 0)
1649e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1650e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            zeros = 0;
1651e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1652e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_1_w32 = WEBRTC_SPL_LSHIFT_W32(sum_log_magn, 1); // Q9
1653e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        sum_log_magn_u16 = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W32(tmp_1_w32, zeros);//Q(9-zeros)
1654e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1655e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Calculate and update pinkNoiseNumerator. Result in Q11.
1656e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square, sum_log_magn_u16); // Q(11-zeros)
1657e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_RSHIFT_U32((WebRtc_UWord32)sum_log_i_log_magn, 12); // Q5
1658e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1659e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Shift the largest value of sum_log_i and tmp32no3 before multiplication
1660e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_u16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)sum_log_i, 1); // Q6
1661e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if ((WebRtc_UWord32)sum_log_i > tmpU32no1)
1662e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1663e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_u16 = WEBRTC_SPL_RSHIFT_U16(tmp_u16, zeros);
1664e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1665e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        else
1666e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1667e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, zeros);
1668e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1669e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_2_w32 -= (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16); // Q(11-zeros)
1670e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        matrix_determinant = WEBRTC_SPL_RSHIFT_W16(matrix_determinant, zeros); // Q(-zeros)
1671e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q11
1672e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_2_w32 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)net_norm, 11); // Q11
1673e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmp_2_w32 < 0)
1674e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1675e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_2_w32 = 0;
1676e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1677e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->pinkNoiseNumerator += tmp_2_w32; // Q11
1678e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1679e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Calculate and update pinkNoiseExp. Result in Q14.
1680e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16); // Q(14-zeros)
1681e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_1_w32 = WEBRTC_SPL_RSHIFT_W32(sum_log_i_log_magn, 3 + zeros);
1682e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_1_w32 = WEBRTC_SPL_MUL((WebRtc_Word32)(inst->magnLen - kStartBand),
1683e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                   tmp_1_w32);
1684e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp_2_w32 -= tmp_1_w32; // Q(14-zeros)
1685e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmp_2_w32 > 0)
1686e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1687e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // If the exponential parameter is negative force it to zero, which means a
1688e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // flat spectrum.
1689e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q14
1690e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0); // Q14
1691e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1692e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1693e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
1694e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1695e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentvoid WebRtcNsx_DataSynthesis(NsxInst_t *inst, short *outFrame)
1696e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
1697e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no1;
1698e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 energyOut;
1699e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1700e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1];
1701e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 tmp16no1, tmp16no2;
1702e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 energyRatio;
1703e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 gainFactor, gainFactor1, gainFactor2;
1704e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1705e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i, j;
1706e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int outCIFFT;
1707e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int scaleEnergyOut = 0;
1708e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1709e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->zeroInputSignal)
1710e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1711e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // synthesize the special case of zero input
1712e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // read out fully processed segment
1713e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < inst->blockLen10ms; i++)
1714e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1715e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            outFrame[i] = inst->synthesisBuffer[i]; // Q0
1716e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1717e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // update synthesis buffer
1718e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer,
1719e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                              inst->synthesisBuffer + inst->blockLen10ms,
1720e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                              inst->anaLen - inst->blockLen10ms);
1721e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms,
1722e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                inst->blockLen10ms);
1723e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return;
1724e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1725e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Filter the data in the frequency domain
1726e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
1727e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1728e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->real[i],
1729e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages)
1730e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->imag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->imag[i],
1731e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages)
1732e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1733e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // back to time domain
1734e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Create spectrum
1735e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    realImag[0] = inst->real[0];
1736e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    realImag[1] = -inst->imag[0];
1737e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 1; i < inst->anaLen2; i++)
1738e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1739e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        j = WEBRTC_SPL_LSHIFT_W16(i, 1);
1740e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 = (inst->anaLen << 1) - j;
1741e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        realImag[j] = inst->real[i];
1742e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        realImag[j + 1] = -inst->imag[i];
1743e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        realImag[tmp16no1] = inst->real[i];
1744e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        realImag[tmp16no1 + 1] = inst->imag[i];
1745e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1746e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    realImag[inst->anaLen] = inst->real[inst->anaLen2];
1747e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    realImag[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
1748e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1749e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // bit-reverse position of elements in array and IFFT it
1750e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ComplexBitReverse(realImag, inst->stages);
1751e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    outCIFFT = WebRtcSpl_ComplexIFFT(realImag, inst->stages, 1);
1752e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1753e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->anaLen; i++)
1754e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1755e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        j = WEBRTC_SPL_LSHIFT_W16(i, 1);
1756e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)realImag[j], outCIFFT - inst->normData);
1757e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1,
1758e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      WEBRTC_SPL_WORD16_MIN);
1759e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1760e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1761e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //scale factor: only do it after END_STARTUP_LONG time
1762e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    gainFactor = 8192; // 8192 = Q13(1.0)
1763e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->gainMap == 1 &&
1764e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->blockIndex > END_STARTUP_LONG &&
1765e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->energyIn > 0)
1766e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1767e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        energyOut = WebRtcSpl_Energy(inst->real, (int)inst->anaLen, &scaleEnergyOut); // Q(-scaleEnergyOut)
1768e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000))
1769e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1770e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            energyOut = WEBRTC_SPL_SHIFT_W32(energyOut, 8 + scaleEnergyOut
1771e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                             - inst->scaleEnergyIn);
1772e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
1773e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1774e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->energyIn = WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 8 + scaleEnergyOut
1775e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                   - inst->scaleEnergyIn); // Q(-8-scaleEnergyOut)
1776e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1777e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1778e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        assert(inst->energyIn > 0);
1779e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        energyRatio = (WebRtc_Word16)WEBRTC_SPL_DIV(energyOut
1780e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                + WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 1), inst->energyIn); // Q8
1781e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1782e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         // original FLOAT code
1783e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         if (gain > blim) {
1784e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         factor1=1.0+1.3*(gain-blim);
1785e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         if (gain*factor1 > 1.0) { // FLOAT
1786e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         factor1 = 1.0/gain; // FLOAT
1787e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         }
1788e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         }
1789e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         else {
1790e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         factor1=1.0; // FLOAT
1791e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         }
1792e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //
1793e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         if (gain > blim) {
1794e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         factor2=1.0; //FLOAT
1795e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         }
1796e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         else {
1797e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         //don't reduce scale too much for pause regions: attenuation here should be controlled by flooring
1798e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         factor2=1.0-0.3*(blim-gain); // FLOAT
1799e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         if (gain <= inst->denoiseBound) {
1800e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         factor2=1.0-0.3*(blim-inst->denoiseBound); // FLOAT
1801e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         }
1802e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //         }
1803e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1804e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // all done in lookup tables now
1805e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gainFactor1 = kFactor1Table[energyRatio]; // Q8
1806e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gainFactor2 = inst->factor2Table[energyRatio]; // Q8
1807e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1808e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //combine both scales with speech/noise prob: note prior (priorSpeechProb) is not frequency dependent
1809e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1810e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // factor = inst->priorSpeechProb*factor1 + (1.0-inst->priorSpeechProb)*factor2; // original code
1811e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(16384 - inst->priorNonSpeechProb,
1812e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                            gainFactor1, 14); // Q13 16384 = Q14(1.0)
1813e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->priorNonSpeechProb,
1814e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                            gainFactor2, 14); // Q13;
1815e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gainFactor = tmp16no1 + tmp16no2; // Q13
1816e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // out of flag_gain_map==1
1817e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1818e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // synthesis
1819e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->anaLen; i++)
1820e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1821e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(inst->window[i],
1822e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                       inst->real[i], 14); // Q0, window in Q14
1823e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16no1, gainFactor, 13); // Q0
1824e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Down shift with rounding
1825e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, tmp32no1,
1826e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                 WEBRTC_SPL_WORD16_MIN); // Q0
1827e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->synthesisBuffer[i] = WEBRTC_SPL_ADD_SAT_W16(inst->synthesisBuffer[i], tmp16no2); // Q0
1828e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1829e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1830e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // read out fully processed segment
1831e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->blockLen10ms; i++)
1832e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1833e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        outFrame[i] = inst->synthesisBuffer[i]; // Q0
1834e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1835e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // update synthesis buffer
1836e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
1837e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                          inst->anaLen - inst->blockLen10ms);
1838e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms,
1839e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                            inst->blockLen10ms);
1840e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
1841e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1842e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurentint WebRtcNsx_ProcessCore(NsxInst_t *inst, short *speechFrame, short *speechFrameHB,
1843e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                          short *outFrame, short *outFrameHB)
1844e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
1845e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // main routine for noise suppression
1846e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1847e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 tmpU32no1, tmpU32no2, tmpU32no3;
1848e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 satMax, maxNoiseU32;
1849e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 tmpMagnU32, tmpNoiseU32;
1850e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 nearMagnEst;
1851e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 noiseUpdateU32;
1852e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 noiseU32[HALF_ANAL_BLOCKL];
1853e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 postLocSnr[HALF_ANAL_BLOCKL];
1854e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 priorLocSnr[HALF_ANAL_BLOCKL];
1855e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 prevNearSnr[HALF_ANAL_BLOCKL];
1856e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 curNearSnr;
1857e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 priorSnr;
1858e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 noise_estimate = 0;
1859e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 noise_estimate_avg = 0;
1860e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord32 numerator = 0;
1861e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1862e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmp32no1, tmp32no2;
1863e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 pink_noise_num_avg = 0;
1864e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1865e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16 tmpU16no1;
1866e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16 magnU16[HALF_ANAL_BLOCKL];
1867e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16 prevNoiseU16[HALF_ANAL_BLOCKL];
1868e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16 nonSpeechProbFinal[HALF_ANAL_BLOCKL];
1869e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16 gammaNoise, prevGammaNoise;
1870e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_UWord16 noiseSupFilterTmp[HALF_ANAL_BLOCKL];
1871e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1872e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 qMagn, qNoise;
1873e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB;
1874e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 tmp16no1;
1875e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 int_part = 0;
1876e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 frac_part = 0;
1877e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 pink_noise_exp_avg = 0;
1878e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1879e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int i;
1880e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int nShifts, postShifts;
1881e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int norm32no1, norm32no2;
1882e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int flag, sign;
1883e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int q_domain_to_use = 0;
1884e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1885e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#ifdef NS_FILEDEBUG
1886e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    fwrite(spframe, sizeof(short), inst->blockLen10ms, inst->infile);
1887e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#endif
1888e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1889e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Check that initialization has been done
1890e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->initFlag != 1)
1891e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1892e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return -1;
1893e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1894e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Check for valid pointers based on sampling rate
1895e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if ((inst->fs == 32000) && (speechFrameHB == NULL))
1896e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1897e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return -1;
1898e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1899e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1900e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Store speechFrame and transform to frequency domain
1901e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_DataAnalysis(inst, speechFrame, magnU16);
1902e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1903e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->zeroInputSignal)
1904e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1905e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WebRtcNsx_DataSynthesis(inst, outFrame);
1906e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1907e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->fs == 32000)
1908e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1909e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // update analysis buffer for H band
1910e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // append new data to buffer FX
1911e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms,
1912e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                  inst->anaLen - inst->blockLen10ms);
1913e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms,
1914e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                  speechFrameHB, inst->blockLen10ms);
1915e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            for (i = 0; i < inst->blockLen10ms; i++)
1916e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1917e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                outFrameHB[i] = inst->dataBufHBFX[i]; // Q0
1918e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1919e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } // end of H band gain computation
1920e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return 0;
1921e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1922e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1923e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Update block index when we have something to process
1924e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->blockIndex++;
1925e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //
1926e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1927e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Norm of magn
1928e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    qMagn = inst->normData - inst->stages;
1929e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1930e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Compute spectral flatness on input spectrum
1931e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_ComputeSpectralFlatness(inst, magnU16);
1932e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1933e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // quantile noise estimate
1934e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise);
1935e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1936e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //noise estimate from previous frame
1937e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
1938e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1939e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        prevNoiseU16[i] = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], 11); // Q(prevQNoise)
1940e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
1941e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1942e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->blockIndex < END_STARTUP_SHORT)
1943e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
1944e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Noise Q-domain to be used later; see description at end of section.
1945e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages);
1946e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1947e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Calculate frequency independent parts in parametric noise estimate and calculate
1948e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // the estimate for the lower frequency band (same values for all frequency bins)
1949e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->pinkNoiseExp)
1950e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1951e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            pink_noise_exp_avg = (WebRtc_Word16)WebRtcSpl_DivW32W16(inst->pinkNoiseExp,
1952e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                (WebRtc_Word16)(inst->blockIndex + 1)); // Q14
1953e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            pink_noise_num_avg = WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator,
1954e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                 (WebRtc_Word16)(inst->blockIndex + 1)); // Q11
1955e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            WebRtcNsx_CalcParametricNoiseEstimate(inst,
1956e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                  pink_noise_exp_avg,
1957e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                  pink_noise_num_avg,
1958e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                  kStartBand,
1959e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                  &noise_estimate,
1960e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                  &noise_estimate_avg);
1961e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1962e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        else
1963e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1964e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Use white noise estimate if we have poor pink noise parameter estimates
1965e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            noise_estimate = inst->whiteNoiseLevel; // Q(minNorm-stages)
1966e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            noise_estimate_avg = noise_estimate / (inst->blockIndex + 1); // Q(minNorm-stages)
1967e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
1968e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < inst->magnLen; i++)
1969e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
1970e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Estimate the background noise using the pink noise parameters if permitted
1971e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if ((inst->pinkNoiseExp) && (i >= kStartBand))
1972e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1973e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Reset noise_estimate
1974e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                noise_estimate = 0;
1975e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                noise_estimate_avg = 0;
1976e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Calculate the parametric noise estimate for current frequency bin
1977e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                WebRtcNsx_CalcParametricNoiseEstimate(inst,
1978e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      pink_noise_exp_avg,
1979e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      pink_noise_num_avg,
1980e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      i,
1981e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      &noise_estimate,
1982e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      &noise_estimate_avg);
1983e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
1984e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Calculate parametric Wiener filter
1985e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            noiseSupFilterTmp[i] = inst->denoiseBound;
1986e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (inst->initMagnEst[i])
1987e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
1988e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // numerator = (initMagnEst - noise_estimate * overdrive)
1989e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Result in Q(8+minNorm-stages)
1990e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive);
1991e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                numerator = WEBRTC_SPL_LSHIFT_U32(inst->initMagnEst[i], 8);
1992e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                if (numerator > tmpU32no1)
1993e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                {
1994e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // Suppression filter coefficient larger than zero, so calculate.
1995e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    numerator -= tmpU32no1;
1996e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
1997e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // Determine number of left shifts in numerator for best accuracy after
1998e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // division
1999e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    nShifts = WebRtcSpl_NormU32(numerator);
2000e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    nShifts = WEBRTC_SPL_SAT(6, nShifts, 0);
2001e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2002e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // Shift numerator to Q(nShifts+8+minNorm-stages)
2003e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    numerator = WEBRTC_SPL_LSHIFT_U32(numerator, nShifts);
2004e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2005e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    // Shift denominator to Q(nShifts-6+minNorm-stages)
2006e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], 6 - nShifts);
2007e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    tmpU32no2 = WEBRTC_SPL_UDIV(numerator, tmpU32no1); // Q14
2008e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    noiseSupFilterTmp[i] = (WebRtc_UWord16)WEBRTC_SPL_SAT(16384, tmpU32no2,
2009e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                           (WebRtc_UWord32)(inst->denoiseBound)); // Q14
2010e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                }
2011e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2012e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Weight quantile noise 'noiseU32' with modeled noise 'noise_estimate_avg'
2013e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // 'noiseU32 is in Q(qNoise) and 'noise_estimate' in Q(minNorm-stages)
2014e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // To guarantee that we do not get wrap around when shifting to the same domain
2015e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // we use the lowest one. Furthermore, we need to save 6 bits for the weighting.
2016e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // 'noise_estimate_avg' can handle this operation by construction, but 'noiseU32'
2017e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // may not.
2018e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2019e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Shift 'noiseU32' to 'q_domain_to_use'
2020e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], (int)qNoise - q_domain_to_use);
2021e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Shift 'noise_estimate_avg' to 'q_domain_to_use'
2022e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noise_estimate_avg, inst->minNorm - inst->stages
2023e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                              - q_domain_to_use);
2024e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Make a simple check to see if we have enough room for weighting 'tmpU32no1'
2025e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // without wrap around
2026e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            nShifts = 0;
2027e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (tmpU32no1 & 0xfc000000) {
2028e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 6);
2029e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6);
2030e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                nShifts = 6;
2031e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2032e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Add them together and divide by startup length
2033e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            noiseU32[i] = WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT);
2034e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Shift back if necessary
2035e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            noiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], nShifts);
2036e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2037e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Update new Q-domain for 'noiseU32'
2038e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        qNoise = q_domain_to_use;
2039e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
2040e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // compute average signal during END_STARTUP_LONG time:
2041e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // used to normalize spectral difference measure
2042e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->blockIndex < END_STARTUP_LONG)
2043e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2044e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // substituting division with shift ending up in Q(-2*stages)
2045e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->timeAvgMagnEnergyTmp
2046e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy,
2047e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                         2 * inst->normData + inst->stages - 1);
2048e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->timeAvgMagnEnergy = WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp,
2049e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      inst->blockIndex + 1);
2050e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
2051e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2052e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //start processing at frames == converged+1
2053e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // STEP 1: compute prior and post SNR based on quantile noise estimates
2054e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2055e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // compute direct decision (DD) estimate of prior SNR: needed for new method
2056e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    satMax = (WebRtc_UWord32)1048575;// Largest possible value without getting overflow despite shifting 12 steps
2057e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    postShifts = 6 + qMagn - qNoise;
2058e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    nShifts = 5 - inst->prevQMagn + inst->prevQNoise;
2059e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
2060e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2061e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // FLOAT:
2062e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // post SNR
2063e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // postLocSnr[i] = 0.0;
2064e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // if (magn[i] > noise[i])
2065e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // {
2066e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //   postLocSnr[i] = magn[i] / (noise[i] + 0.0001);
2067e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // }
2068e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // previous post SNR
2069e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // previous estimate: based on previous frame with gain filter (smooth is previous filter)
2070e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //
2071e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) * (inst->smooth[i]);
2072e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //
2073e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // DD estimate is sum of two terms: current estimate and previous estimate
2074e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // directed decision update of priorSnr (or we actually store [2*priorSnr+1])
2075e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //
2076e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * (postLocSnr[i] - 1.0);
2077e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2078e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // calculate post SNR: output in Q11
2079e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        postLocSnr[i] = 2048; // 1.0 in Q11
2080e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], 6); // Q(6+qMagn)
2081e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (postShifts < 0)
2082e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2083e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], -postShifts); // Q(6+qMagn)
2084e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
2085e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2086e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], postShifts); // Q(6+qMagn)
2087e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2088e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmpU32no1 > tmpU32no2)
2089e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2090e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Current magnitude larger than noise
2091e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, 11); // Q(17+qMagn)
2092e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (tmpU32no2)
2093e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2094e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11
2095e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
2096e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2097e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2098e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                postLocSnr[i] = satMax;
2099e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2100e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2101e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2102e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // calculate prevNearSnr[i] and save for later instead of recalculating it later
2103e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        nearMagnEst = WEBRTC_SPL_UMUL_16_16(inst->prevMagnU16[i], inst->noiseSupFilter[i]); // Q(prevQMagn+14)
2104e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(nearMagnEst, 3); // Q(prevQMagn+17)
2105e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], nShifts); // Q(prevQMagn+6)
2106e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2107e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmpU32no2)
2108e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2109e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_DIV(tmpU32no1, tmpU32no2); // Q11
2110e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
2111e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
2112e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2113e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = satMax; // Q11
2114e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2115e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        prevNearSnr[i] = tmpU32no1; // Q11
2116e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2117e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //directed decision update of priorSnr
2118e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22
2119e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048, ONE_MINUS_DD_PR_SNR_Q11); // Q22
2120e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        priorSnr = tmpU32no1 + tmpU32no2 + 512; // Q22 (added 512 for rounding)
2121e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // priorLocSnr = 1 + 2*priorSnr
2122e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        priorLocSnr[i] = 2048 + WEBRTC_SPL_RSHIFT_U32(priorSnr, 10); // Q11
2123e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // end of loop over frequencies
2124e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // done with step 1: DD computation of prior and post SNR
2125e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2126e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // STEP 2: compute speech/noise likelihood
2127e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2128e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute difference of input spectrum with learned/estimated noise spectrum
2129e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_ComputeSpectralDifference(inst, magnU16);
2130e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute histograms for determination of parameters (thresholds and weights for features)
2131e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //parameters are extracted once every window time (=inst->modelUpdate)
2132e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //counter update
2133e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->cntThresUpdate++;
2134e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    flag = (int)(inst->cntThresUpdate == inst->modelUpdate);
2135e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //update histogram
2136e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_FeatureParameterExtraction(inst, flag);
2137e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute model parameters
2138e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (flag)
2139e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2140e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->cntThresUpdate = 0; // Reset counter
2141e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //update every window:
2142e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // get normalization for spectral difference for next window estimate
2143e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2144e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Shift to Q(-2*stages)
2145e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->curAvgMagnEnergy = WEBRTC_SPL_RSHIFT_U32(inst->curAvgMagnEnergy, STAT_UPDATES);
2146e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2147e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >> 1; //Q(-2*stages)
2148e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Update featureSpecDiff
2149e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff))
2150e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2151e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            norm32no1 = 0;
2152e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no3 = tmpU32no1;
2153e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            while (0xFFFF0000 & tmpU32no3)
2154e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2155e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no3 >>= 1;
2156e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                norm32no1++;
2157e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2158e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = inst->featureSpecDiff;
2159e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            while (0xFFFF0000 & tmpU32no2)
2160e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2161e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no2 >>= 1;
2162e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                norm32no1++;
2163e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2164e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2);
2165e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no3 = WEBRTC_SPL_UDIV(tmpU32no3, inst->timeAvgMagnEnergy);
2166e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1)
2167e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2168e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                inst->featureSpecDiff = 0x007FFFFF;
2169e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2170e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2171e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                inst->featureSpecDiff = WEBRTC_SPL_MIN(0x007FFFFF,
2172e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                        WEBRTC_SPL_LSHIFT_U32(tmpU32no3, norm32no1));
2173e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2174e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2175e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2176e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->timeAvgMagnEnergy = tmpU32no1; // Q(-2*stages)
2177e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->curAvgMagnEnergy = 0;
2178e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
2179e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2180e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //compute speech/noise probability
2181e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr);
2182e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2183e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //time-avg parameter for noise update
2184e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    gammaNoise = NOISE_UPDATE_Q8; // Q8
2185e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2186e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    maxNoiseU32 = 0;
2187e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    postShifts = inst->prevQNoise - qMagn;
2188e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    nShifts = inst->prevQMagn - qMagn;
2189e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
2190e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2191e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // temporary noise update: use it for speech frames if update value is less than previous
2192e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // the formula has been rewritten into:
2193e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i])
2194e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2195e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (postShifts < 0)
2196e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2197e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(magnU16[i], -postShifts); // Q(prevQNoise)
2198e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
2199e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2200e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], postShifts); // Q(prevQNoise)
2201e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2202e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (prevNoiseU16[i] > tmpU32no2)
2203e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2204e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            sign = -1;
2205e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = prevNoiseU16[i] - tmpU32no2;
2206e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
2207e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2208e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            sign = 1;
2209e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = tmpU32no2 - prevNoiseU16[i];
2210e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2211e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        noiseUpdateU32 = inst->prevNoiseU32[i]; // Q(prevQNoise+11)
2212e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no3 = 0;
2213e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if ((tmpU32no1) && (nonSpeechProbFinal[i]))
2214e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2215e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // This value will be used later, if gammaNoise changes
2216e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no3 = WEBRTC_SPL_UMUL_32_16(tmpU32no1, nonSpeechProbFinal[i]); // Q(prevQNoise+8)
2217e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (0x7c000000 & tmpU32no3)
2218e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2219e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Shifting required before multiplication
2220e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no2
2221e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                        = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11)
2222e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2223e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2224e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // We can do shifting after multiplication
2225e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no2
2226e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                        = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11)
2227e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2228e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (sign > 0)
2229e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2230e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                noiseUpdateU32 += tmpU32no2; // Q(prevQNoise+11)
2231e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2232e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2233e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // This operation is safe. We can never get wrap around, since worst
2234e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // case scenario means magnU16 = 0
2235e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                noiseUpdateU32 -= tmpU32no2; // Q(prevQNoise+11)
2236e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2237e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2238e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2239e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //increase gamma (i.e., less noise update) for frame likely to be speech
2240e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        prevGammaNoise = gammaNoise;
2241e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gammaNoise = NOISE_UPDATE_Q8;
2242e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //time-constant based on speech/noise state
2243e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //increase gamma (i.e., less noise update) for frames likely to be speech
2244e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8)
2245e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2246e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8;
2247e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2248e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2249e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (prevGammaNoise != gammaNoise)
2250e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2251e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // new noise update
2252e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // this line is the same as above, only that the result is stored in a different variable and the gammaNoise
2253e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // has changed
2254e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            //
2255e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i])
2256e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2257e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (0x7c000000 & tmpU32no3)
2258e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2259e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // Shifting required before multiplication
2260e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no2
2261e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                        = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11)
2262e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2263e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2264e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                // We can do shifting after multiplication
2265e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no2
2266e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                        = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11)
2267e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2268e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (sign > 0)
2269e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2270e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2; // Q(prevQNoise+11)
2271e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2272e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2273e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2; // Q(prevQNoise+11)
2274e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2275e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (noiseUpdateU32 > tmpU32no1)
2276e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2277e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                noiseUpdateU32 = tmpU32no1; // Q(prevQNoise+11)
2278e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2279e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2280e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        noiseU32[i] = noiseUpdateU32; // Q(prevQNoise+11)
2281e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (noiseUpdateU32 > maxNoiseU32)
2282e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2283e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            maxNoiseU32 = noiseUpdateU32;
2284e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2285e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2286e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // conservative noise update
2287e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // original FLOAT code
2288e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // if (prob_speech < PROB_RANGE) {
2289e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 - gamma_pause)*(magn[i] - inst->avgMagnPause[i]);
2290e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // }
2291e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2292e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts);
2293e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8)
2294e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2295e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (nShifts < 0)
2296e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2297e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = (WebRtc_Word32)magnU16[i] - tmp32no2; // Q(qMagn)
2298e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts)
2299e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + 128, 8); // Q(qMagn)
2300e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            } else
2301e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2302e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)magnU16[i], nShifts)
2303e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                        - inst->avgMagnPause[i]; // Q(qMagn+nShifts)
2304e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts)
2305e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + (128 << nShifts), 8 + nShifts); // Q(qMagn)
2306e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2307e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmp32no2 += tmp32no1; // Q(qMagn)
2308e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2309e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->avgMagnPause[i] = tmp32no2;
2310e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // end of frequency loop
2311e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2312e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    norm32no1 = WebRtcSpl_NormU32(maxNoiseU32);
2313e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    qNoise = inst->prevQNoise + norm32no1 - 5;
2314e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // done with step 2: noise update
2315e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2316e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // STEP 3: compute dd update of prior snr and post snr based on new noise estimate
2317e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    nShifts = inst->prevQNoise + 11 - qMagn;
2318e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    for (i = 0; i < inst->magnLen; i++)
2319e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2320e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // FLOAT code
2321e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // post and prior SNR
2322e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // curNearSnr = 0.0;
2323e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // if (magn[i] > noise[i])
2324e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // {
2325e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0;
2326e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // }
2327e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // DD estimate is sum of two terms: current estimate and previous estimate
2328e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // directed decision update of snrPrior
2329e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr;
2330e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // gain filter
2331e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // tmpFloat1 = inst->overdrive + snrPrior;
2332e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // tmpFloat2 = snrPrior / tmpFloat1;
2333e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // theFilter[i] = tmpFloat2;
2334e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2335e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // calculate curNearSnr again, this is necessary because a new noise estimate has been made since then. for the original
2336e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        curNearSnr = 0; // Q11
2337e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (nShifts < 0)
2338e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2339e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // This case is equivalent with magn < noise which implies curNearSnr = 0;
2340e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpMagnU32 = (WebRtc_UWord32)magnU16[i]; // Q(qMagn)
2341e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpNoiseU32 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], -nShifts); // Q(qMagn)
2342e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else if (nShifts > 17)
2343e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2344e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], 17); // Q(qMagn+17)
2345e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpNoiseU32 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], nShifts - 17); // Q(qMagn+17)
2346e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
2347e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2348e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], nShifts); // Q(qNoise_prev+11)
2349e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpNoiseU32 = noiseU32[i]; // Q(qNoise_prev+11)
2350e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2351e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (tmpMagnU32 > tmpNoiseU32)
2352e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2353e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = tmpMagnU32 - tmpNoiseU32; // Q(qCur)
2354e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1));
2355e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32no2); // Q(qCur+norm32no2)
2356e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpNoiseU32, 11 - norm32no2); // Q(qCur+norm32no2-11)
2357e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            if (tmpU32no2)
2358e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            {
2359e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11
2360e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            }
2361e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
2362e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2363e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2364e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //directed decision update of priorSnr
2365e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // FLOAT
2366e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr;
2367e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2368e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22
2369e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no2 = WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11); // Q22
2370e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        priorSnr = tmpU32no1 + tmpU32no2; // Q22
2371e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2372e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //gain filter
2373e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = (WebRtc_UWord32)(inst->overdrive)
2374e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                + WEBRTC_SPL_RSHIFT_U32(priorSnr + 8192, 14); // Q8
2375e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU16no1 = (WebRtc_UWord16)WEBRTC_SPL_UDIV(priorSnr + (tmpU32no1 >> 1), tmpU32no1); // Q14
2376e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(16384, tmpU16no1, inst->denoiseBound); // 16384 = Q14(1.0) // Q14
2377e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2378e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // Weight in the parametric Wiener filter during startup
2379e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (inst->blockIndex < END_STARTUP_SHORT)
2380e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2381e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // Weight the two suppression filters
2382e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 = WEBRTC_SPL_UMUL_16_16(inst->noiseSupFilter[i],
2383e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                              (WebRtc_UWord16)inst->blockIndex);
2384e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no2 = WEBRTC_SPL_UMUL_16_16(noiseSupFilterTmp[i],
2385e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                              (WebRtc_UWord16)(END_STARTUP_SHORT
2386e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                      - inst->blockIndex));
2387e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 += tmpU32no2;
2388e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->noiseSupFilter[i] = (WebRtc_UWord16)WebRtcSpl_DivU32U16(tmpU32no1,
2389e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                                                          END_STARTUP_SHORT);
2390e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2391e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // end of loop over frequencies
2392e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //done with step3
2393e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2394e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // save noise and magnitude spectrum for next frame
2395e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->prevQNoise = qNoise;
2396e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    inst->prevQMagn = qMagn;
2397e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (norm32no1 > 5)
2398e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2399e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < inst->magnLen; i++)
2400e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2401e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->prevNoiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], norm32no1 - 5); // Q(qNoise+11)
2402e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn)
2403e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2404e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
2405e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2406e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < inst->magnLen; i++)
2407e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2408e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->prevNoiseU32[i] = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], 5 - norm32no1); // Q(qNoise+11)
2409e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn)
2410e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2411e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
2412e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2413e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtcNsx_DataSynthesis(inst, outFrame);
2414e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#ifdef NS_FILEDEBUG
2415e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    fwrite(outframe, sizeof(short), inst->blockLen10ms, inst->outfile);
2416e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#endif
2417e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2418e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    //for H band:
2419e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // only update data buffer, then apply time-domain gain is applied derived from L band
2420e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (inst->fs == 32000)
2421e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
2422e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // update analysis buffer for H band
2423e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // append new data to buffer FX
2424e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, inst->anaLen - inst->blockLen10ms);
2425e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, speechFrameHB, inst->blockLen10ms);
2426e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // range for averaging low band quantities for H band gain
2427e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2428e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gainTimeDomainHB = 16384; // 16384 = Q14(1.0)
2429e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //average speech prob from low band
2430e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //average filter gain from low band
2431e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //avg over second half (i.e., 4->8kHz) of freq. spectrum
2432e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU32no1 = 0; // Q12
2433e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        tmpU16no1 = 0; // Q8
2434e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++)
2435e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2436e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU16no1 += nonSpeechProbFinal[i]; // Q8
2437e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            tmpU32no1 += (WebRtc_UWord32)(inst->noiseSupFilter[i]); // Q14
2438e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2439e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgProbSpeechHB = (WebRtc_Word16)(4096
2440e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                - WEBRTC_SPL_RSHIFT_U16(tmpU16no1, inst->stages - 7)); // Q12
2441e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        avgFilterGainHB = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages - 3); // Q14
2442e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2443e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // original FLOAT code
2444e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // gain based on speech probability:
2445e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0;
2446e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); // between 0 and 1
2447e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2448e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // gain based on speech probability:
2449e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // original expression: "0.5 * (1 + tanh(2x-1))"
2450e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so the other cases don't have to be dealt with
2451e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // avgProbSpeechHB and gainModHB are in Q12, 3607 = Q12(0.880615234375) which is a zero point of
2452e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // |0.5 * (1 + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning that from that point the error of approximating
2453e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // the expression with f(x) = x would be greater than the error of approximating the expression with f(x) = 0.880615234375
2454e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to 0.880615234375" -> http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375
2455e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // and:  "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to 1" -> http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1
2456e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607);
2457e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2458e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // // original FLOAT code
2459e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // //combine gain with low band gain
2460e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // if (avg_prob_speech < (float)0.5) {
2461e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain;
2462e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // }
2463e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // else {
2464e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain;
2465e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        // }
2466e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2467e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2468e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //combine gain with low band gain
2469e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (avgProbSpeechHB < 2048)
2470e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        { // 2048 = Q12(0.5)
2471e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // the next two lines in float are  "gain_time_domain = 0.5 * gain_mod + 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift
2472e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1); // Q14
2473e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        } else
2474e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2475e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;"
2476e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            gainTimeDomainHB = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(3, avgFilterGainHB, 2); // 3 = Q2(0.75); Q14
2477e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            gainTimeDomainHB += gainModHB; // Q14
2478e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2479e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //make sure gain is within flooring range
2480e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        gainTimeDomainHB
2481e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                = WEBRTC_SPL_SAT(16384, gainTimeDomainHB, (WebRtc_Word16)(inst->denoiseBound)); // 16384 = Q14(1.0)
2482e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2483e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2484e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        //apply gain
2485e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        for (i = 0; i < inst->blockLen10ms; i++)
2486e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
2487e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            outFrameHB[i]
2488e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                    = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gainTimeDomainHB, inst->dataBufHBFX[i], 14); // Q0
2489e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
2490e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } // end of H band gain computation
2491e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
2492e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    return 0;
2493e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
2494