diff options
Diffstat (limited to 'src/common_audio/vad/vad_sp.c')
-rw-r--r-- | src/common_audio/vad/vad_sp.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src/common_audio/vad/vad_sp.c b/src/common_audio/vad/vad_sp.c new file mode 100644 index 0000000000..4fface3a64 --- /dev/null +++ b/src/common_audio/vad/vad_sp.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "vad_sp.h" + +#include <assert.h> + +#include "signal_processing_library.h" +#include "typedefs.h" +#include "vad_defines.h" + +// Allpass filter coefficients, upper and lower, in Q13. +// Upper: 0.64, Lower: 0.17. +static const int16_t kAllPassCoefsQ13[2] = { 5243, 1392 }; // Q13 + +// TODO(bjornv): Move this function to vad_filterbank.c. +// Downsampling filter based on splitting filter and allpass functions. +void WebRtcVad_Downsampling(int16_t* signal_in, + int16_t* signal_out, + int32_t* filter_state, + int in_length) { + int16_t tmp16_1 = 0, tmp16_2 = 0; + int32_t tmp32_1 = filter_state[0]; + int32_t tmp32_2 = filter_state[1]; + int n = 0; + int half_length = (in_length >> 1); // Downsampling by 2 gives half length. + + // Filter coefficients in Q13, filter state in Q0. + for (n = 0; n < half_length; n++) { + // All-pass filtering upper branch. + tmp16_1 = (int16_t) ((tmp32_1 >> 1) + + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[0], *signal_in, 14)); + *signal_out = tmp16_1; + tmp32_1 = (int32_t) (*signal_in++) - + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[0], tmp16_1, 12); + + // All-pass filtering lower branch. + tmp16_2 = (int16_t) ((tmp32_2 >> 1) + + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[1], *signal_in, 14)); + *signal_out++ += tmp16_2; + tmp32_2 = (int32_t) (*signal_in++) - + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[1], tmp16_2, 12); + } + // Store the filter states. + filter_state[0] = tmp32_1; + filter_state[1] = tmp32_2; +} + +// Inserts |feature_value| into |low_value_vector|, if it is one of the 16 +// smallest values the last 100 frames. Then calculates and returns the median +// of the five smallest values. +int16_t WebRtcVad_FindMinimum(VadInstT* self, + int16_t feature_value, + int channel) { + int i = 0, j = 0; + int position = -1; + // Offset to beginning of the 16 minimum values in memory. + int offset = (channel << 4); + int16_t current_median = 1600; + int16_t alpha = 0; + int32_t tmp32 = 0; + // Pointer to memory for the 16 minimum values and the age of each value of + // the |channel|. + int16_t* age_ptr = &self->index_vector[offset]; + int16_t* value_ptr = &self->low_value_vector[offset]; + int16_t *p1, *p2, *p3; + + assert(channel < NUM_CHANNELS); + + // Each value in |low_value_vector| is getting 1 loop older. + // Update age of each value in |age_ptr|, and remove old values. + for (i = 0; i < 16; i++) { + p3 = age_ptr + i; + if (*p3 != 100) { + *p3 += 1; + } else { + p1 = value_ptr + i + 1; + p2 = p3 + 1; + for (j = i; j < 16; j++) { + *(value_ptr + j) = *p1++; + *(age_ptr + j) = *p2++; + } + *(age_ptr + 15) = 101; + *(value_ptr + 15) = 10000; + } + } + + // Check if |feature_value| is smaller than any of the values in + // |low_value_vector|. If so, find the |position| where to insert the new + // value. + if (feature_value < *(value_ptr + 7)) { + if (feature_value < *(value_ptr + 3)) { + if (feature_value < *(value_ptr + 1)) { + if (feature_value < *value_ptr) { + position = 0; + } else { + position = 1; + } + } else if (feature_value < *(value_ptr + 2)) { + position = 2; + } else { + position = 3; + } + } else if (feature_value < *(value_ptr + 5)) { + if (feature_value < *(value_ptr + 4)) { + position = 4; + } else { + position = 5; + } + } else if (feature_value < *(value_ptr + 6)) { + position = 6; + } else { + position = 7; + } + } else if (feature_value < *(value_ptr + 15)) { + if (feature_value < *(value_ptr + 11)) { + if (feature_value < *(value_ptr + 9)) { + if (feature_value < *(value_ptr + 8)) { + position = 8; + } else { + position = 9; + } + } else if (feature_value < *(value_ptr + 10)) { + position = 10; + } else { + position = 11; + } + } else if (feature_value < *(value_ptr + 13)) { + if (feature_value < *(value_ptr + 12)) { + position = 12; + } else { + position = 13; + } + } else if (feature_value < *(value_ptr + 14)) { + position = 14; + } else { + position = 15; + } + } + + // If we have a new small value, put it in the correct position and shift + // larger values up. + if (position > -1) { + for (i = 15; i > position; i--) { + j = i - 1; + *(value_ptr + i) = *(value_ptr + j); + *(age_ptr + i) = *(age_ptr + j); + } + *(value_ptr + position) = feature_value; + *(age_ptr + position) = 1; + } + + // Get |current_median|. + if (self->frame_counter > 2) { + current_median = *(value_ptr + 2); + } else if (self->frame_counter > 0) { + current_median = *value_ptr; + } + + // Smooth the median value. + if (self->frame_counter > 0) { + if (current_median < self->mean_value[channel]) { + alpha = (int16_t) ALPHA1; // 0.2 in Q15. + } else { + alpha = (int16_t) ALPHA2; // 0.99 in Q15. + } + } + tmp32 = WEBRTC_SPL_MUL_16_16(alpha + 1, self->mean_value[channel]); + tmp32 += WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX - alpha, current_median); + tmp32 += 16384; + self->mean_value[channel] = (int16_t) (tmp32 >> 15); + + return self->mean_value[channel]; +} |