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