1c55a96383497a772a307b346368133960b02ad03Eric Laurent/*
2c55a96383497a772a307b346368133960b02ad03Eric Laurent *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3c55a96383497a772a307b346368133960b02ad03Eric Laurent *
4c55a96383497a772a307b346368133960b02ad03Eric Laurent *  Use of this source code is governed by a BSD-style license
5c55a96383497a772a307b346368133960b02ad03Eric Laurent *  that can be found in the LICENSE file in the root of the source
6c55a96383497a772a307b346368133960b02ad03Eric Laurent *  tree. An additional intellectual property rights grant can be found
7c55a96383497a772a307b346368133960b02ad03Eric Laurent *  in the file PATENTS.  All contributing project authors may
8c55a96383497a772a307b346368133960b02ad03Eric Laurent *  be found in the AUTHORS file in the root of the source tree.
9c55a96383497a772a307b346368133960b02ad03Eric Laurent */
10c55a96383497a772a307b346368133960b02ad03Eric Laurent
11c55a96383497a772a307b346368133960b02ad03Eric Laurent/*
12c55a96383497a772a307b346368133960b02ad03Eric Laurent * This file includes the implementation of the internal filterbank associated functions.
13c55a96383497a772a307b346368133960b02ad03Eric Laurent * For function description, see vad_filterbank.h.
14c55a96383497a772a307b346368133960b02ad03Eric Laurent */
15c55a96383497a772a307b346368133960b02ad03Eric Laurent
16c55a96383497a772a307b346368133960b02ad03Eric Laurent#include "vad_filterbank.h"
17c55a96383497a772a307b346368133960b02ad03Eric Laurent
18c55a96383497a772a307b346368133960b02ad03Eric Laurent#include "signal_processing_library.h"
19c55a96383497a772a307b346368133960b02ad03Eric Laurent#include "typedefs.h"
20c55a96383497a772a307b346368133960b02ad03Eric Laurent#include "vad_defines.h"
21c55a96383497a772a307b346368133960b02ad03Eric Laurent
22c55a96383497a772a307b346368133960b02ad03Eric Laurent// Constant 160*log10(2) in Q9
23c55a96383497a772a307b346368133960b02ad03Eric Laurentstatic const int16_t kLogConst = 24660;
24c55a96383497a772a307b346368133960b02ad03Eric Laurent
25c55a96383497a772a307b346368133960b02ad03Eric Laurent// Coefficients used by WebRtcVad_HpOutput, Q14
26c55a96383497a772a307b346368133960b02ad03Eric Laurentstatic const int16_t kHpZeroCoefs[3] = { 6631, -13262, 6631 };
27c55a96383497a772a307b346368133960b02ad03Eric Laurentstatic const int16_t kHpPoleCoefs[3] = { 16384, -7756, 5620 };
28c55a96383497a772a307b346368133960b02ad03Eric Laurent
29c55a96383497a772a307b346368133960b02ad03Eric Laurent// Allpass filter coefficients, upper and lower, in Q15
30c55a96383497a772a307b346368133960b02ad03Eric Laurent// Upper: 0.64, Lower: 0.17
31c55a96383497a772a307b346368133960b02ad03Eric Laurentstatic const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 };
32c55a96383497a772a307b346368133960b02ad03Eric Laurent
33c55a96383497a772a307b346368133960b02ad03Eric Laurent// Adjustment for division with two in WebRtcVad_SplitFilter
34c55a96383497a772a307b346368133960b02ad03Eric Laurentstatic const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 };
35c55a96383497a772a307b346368133960b02ad03Eric Laurent
36c55a96383497a772a307b346368133960b02ad03Eric Laurentvoid WebRtcVad_HpOutput(int16_t* in_vector,
37c55a96383497a772a307b346368133960b02ad03Eric Laurent                        int in_vector_length,
38c55a96383497a772a307b346368133960b02ad03Eric Laurent                        int16_t* filter_state,
39c55a96383497a772a307b346368133960b02ad03Eric Laurent                        int16_t* out_vector) {
40c55a96383497a772a307b346368133960b02ad03Eric Laurent  int i;
41c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t* in_ptr = in_vector;
42c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t* out_ptr = out_vector;
43c55a96383497a772a307b346368133960b02ad03Eric Laurent  int32_t tmp32 = 0;
44c55a96383497a772a307b346368133960b02ad03Eric Laurent
45c55a96383497a772a307b346368133960b02ad03Eric Laurent
46c55a96383497a772a307b346368133960b02ad03Eric Laurent  // The sum of the absolute values of the impulse response:
47c55a96383497a772a307b346368133960b02ad03Eric Laurent  // The zero/pole-filter has a max amplification of a single sample of: 1.4546
48c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Impulse response: 0.4047 -0.6179 -0.0266  0.1993  0.1035  -0.0194
49c55a96383497a772a307b346368133960b02ad03Eric Laurent  // The all-zero section has a max amplification of a single sample of: 1.6189
50c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Impulse response: 0.4047 -0.8094  0.4047  0       0        0
51c55a96383497a772a307b346368133960b02ad03Eric Laurent  // The all-pole section has a max amplification of a single sample of: 1.9931
52c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Impulse response: 1.0000  0.4734 -0.1189 -0.2187 -0.0627   0.04532
53c55a96383497a772a307b346368133960b02ad03Eric Laurent
54c55a96383497a772a307b346368133960b02ad03Eric Laurent  for (i = 0; i < in_vector_length; i++) {
55c55a96383497a772a307b346368133960b02ad03Eric Laurent    // all-zero section (filter coefficients in Q14)
56c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp32 = (int32_t) WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[0], (*in_ptr));
57c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp32 += (int32_t) WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[1], filter_state[0]);
58c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp32 += (int32_t) WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[2],
59c55a96383497a772a307b346368133960b02ad03Eric Laurent                                            filter_state[1]);  // Q14
60c55a96383497a772a307b346368133960b02ad03Eric Laurent    filter_state[1] = filter_state[0];
61c55a96383497a772a307b346368133960b02ad03Eric Laurent    filter_state[0] = *in_ptr++;
62c55a96383497a772a307b346368133960b02ad03Eric Laurent
63c55a96383497a772a307b346368133960b02ad03Eric Laurent    // all-pole section
64c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp32 -= (int32_t) WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[1],
65c55a96383497a772a307b346368133960b02ad03Eric Laurent                                            filter_state[2]);  // Q14
66c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp32 -= (int32_t) WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[2], filter_state[3]);
67c55a96383497a772a307b346368133960b02ad03Eric Laurent    filter_state[3] = filter_state[2];
68c55a96383497a772a307b346368133960b02ad03Eric Laurent    filter_state[2] = (int16_t) WEBRTC_SPL_RSHIFT_W32 (tmp32, 14);
69c55a96383497a772a307b346368133960b02ad03Eric Laurent    *out_ptr++ = filter_state[2];
70c55a96383497a772a307b346368133960b02ad03Eric Laurent  }
71c55a96383497a772a307b346368133960b02ad03Eric Laurent}
72c55a96383497a772a307b346368133960b02ad03Eric Laurent
73c55a96383497a772a307b346368133960b02ad03Eric Laurentvoid WebRtcVad_Allpass(int16_t* in_vector,
74c55a96383497a772a307b346368133960b02ad03Eric Laurent                       int16_t filter_coefficients,
75c55a96383497a772a307b346368133960b02ad03Eric Laurent                       int vector_length,
76c55a96383497a772a307b346368133960b02ad03Eric Laurent                       int16_t* filter_state,
77c55a96383497a772a307b346368133960b02ad03Eric Laurent                       int16_t* out_vector) {
78c55a96383497a772a307b346368133960b02ad03Eric Laurent  // The filter can only cause overflow (in the w16 output variable)
79c55a96383497a772a307b346368133960b02ad03Eric Laurent  // if more than 4 consecutive input numbers are of maximum value and
80c55a96383497a772a307b346368133960b02ad03Eric Laurent  // has the the same sign as the impulse responses first taps.
81c55a96383497a772a307b346368133960b02ad03Eric Laurent  // First 6 taps of the impulse response: 0.6399 0.5905 -0.3779
82c55a96383497a772a307b346368133960b02ad03Eric Laurent  // 0.2418 -0.1547 0.0990
83c55a96383497a772a307b346368133960b02ad03Eric Laurent
84c55a96383497a772a307b346368133960b02ad03Eric Laurent  int i;
85c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t tmp16 = 0;
86c55a96383497a772a307b346368133960b02ad03Eric Laurent  int32_t tmp32 = 0, in32 = 0;
87c55a96383497a772a307b346368133960b02ad03Eric Laurent  int32_t state32 = WEBRTC_SPL_LSHIFT_W32((int32_t) (*filter_state), 16); // Q31
88c55a96383497a772a307b346368133960b02ad03Eric Laurent
89c55a96383497a772a307b346368133960b02ad03Eric Laurent  for (i = 0; i < vector_length; i++) {
90c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp32 = state32 + WEBRTC_SPL_MUL_16_16(filter_coefficients, (*in_vector));
91c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32, 16);
92c55a96383497a772a307b346368133960b02ad03Eric Laurent    *out_vector++ = tmp16;
93c55a96383497a772a307b346368133960b02ad03Eric Laurent    in32 = WEBRTC_SPL_LSHIFT_W32(((int32_t) (*in_vector)), 14);
94c55a96383497a772a307b346368133960b02ad03Eric Laurent    state32 = in32 - WEBRTC_SPL_MUL_16_16(filter_coefficients, tmp16);
95c55a96383497a772a307b346368133960b02ad03Eric Laurent    state32 = WEBRTC_SPL_LSHIFT_W32(state32, 1);
96c55a96383497a772a307b346368133960b02ad03Eric Laurent    in_vector += 2;
97c55a96383497a772a307b346368133960b02ad03Eric Laurent  }
98c55a96383497a772a307b346368133960b02ad03Eric Laurent
99c55a96383497a772a307b346368133960b02ad03Eric Laurent  *filter_state = (int16_t) WEBRTC_SPL_RSHIFT_W32(state32, 16);
100c55a96383497a772a307b346368133960b02ad03Eric Laurent}
101c55a96383497a772a307b346368133960b02ad03Eric Laurent
102c55a96383497a772a307b346368133960b02ad03Eric Laurentvoid WebRtcVad_SplitFilter(int16_t* in_vector,
103c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int in_vector_length,
104c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t* upper_state,
105c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t* lower_state,
106c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t* out_vector_hp,
107c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t* out_vector_lp) {
108c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t tmp_out;
109c55a96383497a772a307b346368133960b02ad03Eric Laurent  int i;
110c55a96383497a772a307b346368133960b02ad03Eric Laurent  int half_length = WEBRTC_SPL_RSHIFT_W16(in_vector_length, 1);
111c55a96383497a772a307b346368133960b02ad03Eric Laurent
112c55a96383497a772a307b346368133960b02ad03Eric Laurent  // All-pass filtering upper branch
113c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_Allpass(&in_vector[0], kAllPassCoefsQ15[0], half_length,
114c55a96383497a772a307b346368133960b02ad03Eric Laurent                    upper_state, out_vector_hp);
115c55a96383497a772a307b346368133960b02ad03Eric Laurent
116c55a96383497a772a307b346368133960b02ad03Eric Laurent  // All-pass filtering lower branch
117c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_Allpass(&in_vector[1], kAllPassCoefsQ15[1], half_length,
118c55a96383497a772a307b346368133960b02ad03Eric Laurent                    lower_state, out_vector_lp);
119c55a96383497a772a307b346368133960b02ad03Eric Laurent
120c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Make LP and HP signals
121c55a96383497a772a307b346368133960b02ad03Eric Laurent  for (i = 0; i < half_length; i++) {
122c55a96383497a772a307b346368133960b02ad03Eric Laurent    tmp_out = *out_vector_hp;
123c55a96383497a772a307b346368133960b02ad03Eric Laurent    *out_vector_hp++ -= *out_vector_lp;
124c55a96383497a772a307b346368133960b02ad03Eric Laurent    *out_vector_lp++ += tmp_out;
125c55a96383497a772a307b346368133960b02ad03Eric Laurent  }
126c55a96383497a772a307b346368133960b02ad03Eric Laurent}
127c55a96383497a772a307b346368133960b02ad03Eric Laurent
128c55a96383497a772a307b346368133960b02ad03Eric Laurentint16_t WebRtcVad_get_features(VadInstT* inst,
129c55a96383497a772a307b346368133960b02ad03Eric Laurent                               int16_t* in_vector,
130c55a96383497a772a307b346368133960b02ad03Eric Laurent                               int frame_size,
131c55a96383497a772a307b346368133960b02ad03Eric Laurent                               int16_t* out_vector) {
132c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t power = 0;
133c55a96383497a772a307b346368133960b02ad03Eric Laurent  // We expect |frame_size| to be 80, 160 or 240 samples, which corresponds to
134c55a96383497a772a307b346368133960b02ad03Eric Laurent  // 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will
135c55a96383497a772a307b346368133960b02ad03Eric Laurent  // have at most 120 samples after the first split and at most 60 samples after
136c55a96383497a772a307b346368133960b02ad03Eric Laurent  // the second split.
137c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t hp_120[120], lp_120[120];
138c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t hp_60[60], lp_60[60];
139c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Initialize variables for the first SplitFilter().
140c55a96383497a772a307b346368133960b02ad03Eric Laurent  int length = frame_size;
141c55a96383497a772a307b346368133960b02ad03Eric Laurent  int frequency_band = 0;
142c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t* in_ptr = in_vector;
143c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t* hp_out_ptr = hp_120;
144c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t* lp_out_ptr = lp_120;
145c55a96383497a772a307b346368133960b02ad03Eric Laurent
146c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Split at 2000 Hz and downsample
147c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_SplitFilter(in_ptr, length, &inst->upper_state[frequency_band],
148c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &inst->lower_state[frequency_band], hp_out_ptr,
149c55a96383497a772a307b346368133960b02ad03Eric Laurent                        lp_out_ptr);
150c55a96383497a772a307b346368133960b02ad03Eric Laurent
151c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Split at 3000 Hz and downsample
152c55a96383497a772a307b346368133960b02ad03Eric Laurent  frequency_band = 1;
153c55a96383497a772a307b346368133960b02ad03Eric Laurent  in_ptr = hp_120;
154c55a96383497a772a307b346368133960b02ad03Eric Laurent  hp_out_ptr = hp_60;
155c55a96383497a772a307b346368133960b02ad03Eric Laurent  lp_out_ptr = lp_60;
156c55a96383497a772a307b346368133960b02ad03Eric Laurent  length = WEBRTC_SPL_RSHIFT_W16(frame_size, 1);
157c55a96383497a772a307b346368133960b02ad03Eric Laurent
158c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_SplitFilter(in_ptr, length, &inst->upper_state[frequency_band],
159c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &inst->lower_state[frequency_band], hp_out_ptr,
160c55a96383497a772a307b346368133960b02ad03Eric Laurent                        lp_out_ptr);
161c55a96383497a772a307b346368133960b02ad03Eric Laurent
162c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Energy in 3000 Hz - 4000 Hz
163c55a96383497a772a307b346368133960b02ad03Eric Laurent  length = WEBRTC_SPL_RSHIFT_W16(length, 1);
164c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_LogOfEnergy(hp_60, length, kOffsetVector[5], &power,
165c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &out_vector[5]);
166c55a96383497a772a307b346368133960b02ad03Eric Laurent
167c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Energy in 2000 Hz - 3000 Hz
168c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_LogOfEnergy(lp_60, length, kOffsetVector[4], &power,
169c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &out_vector[4]);
170c55a96383497a772a307b346368133960b02ad03Eric Laurent
171c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Split at 1000 Hz and downsample
172c55a96383497a772a307b346368133960b02ad03Eric Laurent  frequency_band = 2;
173c55a96383497a772a307b346368133960b02ad03Eric Laurent  in_ptr = lp_120;
174c55a96383497a772a307b346368133960b02ad03Eric Laurent  hp_out_ptr = hp_60;
175c55a96383497a772a307b346368133960b02ad03Eric Laurent  lp_out_ptr = lp_60;
176c55a96383497a772a307b346368133960b02ad03Eric Laurent  length = WEBRTC_SPL_RSHIFT_W16(frame_size, 1);
177c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_SplitFilter(in_ptr, length, &inst->upper_state[frequency_band],
178c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &inst->lower_state[frequency_band], hp_out_ptr,
179c55a96383497a772a307b346368133960b02ad03Eric Laurent                        lp_out_ptr);
180c55a96383497a772a307b346368133960b02ad03Eric Laurent
181c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Energy in 1000 Hz - 2000 Hz
182c55a96383497a772a307b346368133960b02ad03Eric Laurent  length = WEBRTC_SPL_RSHIFT_W16(length, 1);
183c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_LogOfEnergy(hp_60, length, kOffsetVector[3], &power,
184c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &out_vector[3]);
185c55a96383497a772a307b346368133960b02ad03Eric Laurent
186c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Split at 500 Hz
187c55a96383497a772a307b346368133960b02ad03Eric Laurent  frequency_band = 3;
188c55a96383497a772a307b346368133960b02ad03Eric Laurent  in_ptr = lp_60;
189c55a96383497a772a307b346368133960b02ad03Eric Laurent  hp_out_ptr = hp_120;
190c55a96383497a772a307b346368133960b02ad03Eric Laurent  lp_out_ptr = lp_120;
191c55a96383497a772a307b346368133960b02ad03Eric Laurent
192c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_SplitFilter(in_ptr, length, &inst->upper_state[frequency_band],
193c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &inst->lower_state[frequency_band], hp_out_ptr,
194c55a96383497a772a307b346368133960b02ad03Eric Laurent                        lp_out_ptr);
195c55a96383497a772a307b346368133960b02ad03Eric Laurent
196c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Energy in 500 Hz - 1000 Hz
197c55a96383497a772a307b346368133960b02ad03Eric Laurent  length = WEBRTC_SPL_RSHIFT_W16(length, 1);
198c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_LogOfEnergy(hp_120, length, kOffsetVector[2], &power,
199c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &out_vector[2]);
200c55a96383497a772a307b346368133960b02ad03Eric Laurent
201c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Split at 250 Hz
202c55a96383497a772a307b346368133960b02ad03Eric Laurent  frequency_band = 4;
203c55a96383497a772a307b346368133960b02ad03Eric Laurent  in_ptr = lp_120;
204c55a96383497a772a307b346368133960b02ad03Eric Laurent  hp_out_ptr = hp_60;
205c55a96383497a772a307b346368133960b02ad03Eric Laurent  lp_out_ptr = lp_60;
206c55a96383497a772a307b346368133960b02ad03Eric Laurent
207c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_SplitFilter(in_ptr, length, &inst->upper_state[frequency_band],
208c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &inst->lower_state[frequency_band], hp_out_ptr,
209c55a96383497a772a307b346368133960b02ad03Eric Laurent                        lp_out_ptr);
210c55a96383497a772a307b346368133960b02ad03Eric Laurent
211c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Energy in 250 Hz - 500 Hz
212c55a96383497a772a307b346368133960b02ad03Eric Laurent  length = WEBRTC_SPL_RSHIFT_W16(length, 1);
213c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_LogOfEnergy(hp_60, length, kOffsetVector[1], &power,
214c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &out_vector[1]);
215c55a96383497a772a307b346368133960b02ad03Eric Laurent
216c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Remove DC and LFs
217c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_HpOutput(lp_60, length, inst->hp_filter_state, hp_120);
218c55a96383497a772a307b346368133960b02ad03Eric Laurent
219c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Power in 80 Hz - 250 Hz
220c55a96383497a772a307b346368133960b02ad03Eric Laurent  WebRtcVad_LogOfEnergy(hp_120, length, kOffsetVector[0], &power,
221c55a96383497a772a307b346368133960b02ad03Eric Laurent                        &out_vector[0]);
222c55a96383497a772a307b346368133960b02ad03Eric Laurent
223c55a96383497a772a307b346368133960b02ad03Eric Laurent  return power;
224c55a96383497a772a307b346368133960b02ad03Eric Laurent}
225c55a96383497a772a307b346368133960b02ad03Eric Laurent
226c55a96383497a772a307b346368133960b02ad03Eric Laurentvoid WebRtcVad_LogOfEnergy(int16_t* vector,
227c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int vector_length,
228c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t offset,
229c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t* power,
230c55a96383497a772a307b346368133960b02ad03Eric Laurent                           int16_t* log_energy) {
231c55a96383497a772a307b346368133960b02ad03Eric Laurent  int shfts = 0, shfts2 = 0;
232c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t energy_s16 = 0;
233c55a96383497a772a307b346368133960b02ad03Eric Laurent  int16_t zeros = 0, frac = 0, log2 = 0;
234c55a96383497a772a307b346368133960b02ad03Eric Laurent  int32_t energy = WebRtcSpl_Energy(vector, vector_length, &shfts);
235c55a96383497a772a307b346368133960b02ad03Eric Laurent
236c55a96383497a772a307b346368133960b02ad03Eric Laurent  if (energy > 0) {
237c55a96383497a772a307b346368133960b02ad03Eric Laurent
238c55a96383497a772a307b346368133960b02ad03Eric Laurent    shfts2 = 16 - WebRtcSpl_NormW32(energy);
239c55a96383497a772a307b346368133960b02ad03Eric Laurent    shfts += shfts2;
240c55a96383497a772a307b346368133960b02ad03Eric Laurent    // "shfts" is the total number of right shifts that has been done to
241c55a96383497a772a307b346368133960b02ad03Eric Laurent    // energy_s16.
242c55a96383497a772a307b346368133960b02ad03Eric Laurent    energy_s16 = (int16_t) WEBRTC_SPL_SHIFT_W32(energy, -shfts2);
243c55a96383497a772a307b346368133960b02ad03Eric Laurent
244c55a96383497a772a307b346368133960b02ad03Eric Laurent    // Find:
245c55a96383497a772a307b346368133960b02ad03Eric Laurent    // 160*log10(energy_s16*2^shfts) = 160*log10(2)*log2(energy_s16*2^shfts) =
246c55a96383497a772a307b346368133960b02ad03Eric Laurent    // 160*log10(2)*(log2(energy_s16) + log2(2^shfts)) =
247c55a96383497a772a307b346368133960b02ad03Eric Laurent    // 160*log10(2)*(log2(energy_s16) + shfts)
248c55a96383497a772a307b346368133960b02ad03Eric Laurent
249c55a96383497a772a307b346368133960b02ad03Eric Laurent    zeros = WebRtcSpl_NormU32(energy_s16);
250c55a96383497a772a307b346368133960b02ad03Eric Laurent    frac = (int16_t) (((uint32_t) ((int32_t) (energy_s16) << zeros)
251c55a96383497a772a307b346368133960b02ad03Eric Laurent        & 0x7FFFFFFF) >> 21);
252c55a96383497a772a307b346368133960b02ad03Eric Laurent    log2 = (int16_t) (((31 - zeros) << 10) + frac);
253c55a96383497a772a307b346368133960b02ad03Eric Laurent
254c55a96383497a772a307b346368133960b02ad03Eric Laurent    *log_energy = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(kLogConst, log2, 19)
255c55a96383497a772a307b346368133960b02ad03Eric Laurent        + (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(shfts, kLogConst, 9);
256c55a96383497a772a307b346368133960b02ad03Eric Laurent
257c55a96383497a772a307b346368133960b02ad03Eric Laurent    if (*log_energy < 0) {
258c55a96383497a772a307b346368133960b02ad03Eric Laurent      *log_energy = 0;
259c55a96383497a772a307b346368133960b02ad03Eric Laurent    }
260c55a96383497a772a307b346368133960b02ad03Eric Laurent  } else {
261c55a96383497a772a307b346368133960b02ad03Eric Laurent    *log_energy = 0;
262c55a96383497a772a307b346368133960b02ad03Eric Laurent    shfts = -15;
263c55a96383497a772a307b346368133960b02ad03Eric Laurent    energy_s16 = 0;
264c55a96383497a772a307b346368133960b02ad03Eric Laurent  }
265c55a96383497a772a307b346368133960b02ad03Eric Laurent
266c55a96383497a772a307b346368133960b02ad03Eric Laurent  *log_energy += offset;
267c55a96383497a772a307b346368133960b02ad03Eric Laurent
268c55a96383497a772a307b346368133960b02ad03Eric Laurent  // Total power in frame
269c55a96383497a772a307b346368133960b02ad03Eric Laurent  if (*power <= MIN_ENERGY) {
270c55a96383497a772a307b346368133960b02ad03Eric Laurent    if (shfts > 0) {
271c55a96383497a772a307b346368133960b02ad03Eric Laurent      *power += MIN_ENERGY + 1;
272c55a96383497a772a307b346368133960b02ad03Eric Laurent    } else if (WEBRTC_SPL_SHIFT_W16(energy_s16, shfts) > MIN_ENERGY) {
273c55a96383497a772a307b346368133960b02ad03Eric Laurent      *power += MIN_ENERGY + 1;
274c55a96383497a772a307b346368133960b02ad03Eric Laurent    } else {
275c55a96383497a772a307b346368133960b02ad03Eric Laurent      *power += WEBRTC_SPL_SHIFT_W16(energy_s16, shfts);
276c55a96383497a772a307b346368133960b02ad03Eric Laurent    }
277c55a96383497a772a307b346368133960b02ad03Eric Laurent  }
278c55a96383497a772a307b346368133960b02ad03Eric Laurent}
279