| /* Copyright 2020 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "ewma_power.h" |
| #include "math.h" |
| |
| /* One sample per 1ms. */ |
| #define EWMA_SAMPLE_RATE 1000 |
| |
| /* Smooth factor for EWMA, 1 - expf(-1.0/(rate * 0.01)) |
| * where the 0.01 corresponds to 10ms interval that is chosen and |
| * being used in Chrome for a long time. |
| * Here the |rate| is set to the down sampled EWMA_SAMPLE_RATE and |
| * whenever it changes the calculated |smooth_factor| should be updated |
| * accordingly. |
| */ |
| const static float smooth_factor = 0.095; |
| |
| void ewma_power_disable(struct ewma_power *ewma) |
| { |
| ewma->enabled = 0; |
| } |
| |
| void ewma_power_init(struct ewma_power *ewma, unsigned int rate) |
| { |
| ewma->enabled = 1; |
| ewma->power_set = 0; |
| ewma->step_fr = rate / EWMA_SAMPLE_RATE; |
| } |
| |
| void ewma_power_calculate(struct ewma_power *ewma, const int16_t *buf, |
| unsigned int channels, unsigned int size) |
| { |
| int i, ch; |
| float power, f; |
| |
| if (!ewma->enabled) |
| return; |
| for (i = 0; i < size; i += ewma->step_fr * channels) { |
| power = 0.0f; |
| for (ch = 0; ch < channels; ch++) { |
| f = buf[i + ch] / 32768.0f; |
| power += f * f / channels; |
| } |
| if (!ewma->power_set) { |
| ewma->power = power; |
| ewma->power_set = 1; |
| } else { |
| ewma->power = smooth_factor * power + |
| (1 - smooth_factor) * ewma->power; |
| } |
| } |
| } |
| |
| void ewma_power_calculate_area(struct ewma_power *ewma, const int16_t *buf, |
| struct cras_audio_area *area, unsigned int size) |
| { |
| int i, ch; |
| float power, f; |
| |
| if (!ewma->enabled) |
| return; |
| for (i = 0; i < size; i += ewma->step_fr * area->num_channels) { |
| power = 0.0f; |
| for (ch = 0; ch < area->num_channels; ch++) { |
| if (area->channels[ch].ch_set == 0) |
| continue; |
| f = buf[i + ch] / 32768.0f; |
| power += f * f / area->num_channels; |
| } |
| if (!ewma->power_set) { |
| ewma->power = power; |
| ewma->power_set = 1; |
| } else { |
| ewma->power = smooth_factor * power + |
| (1 - smooth_factor) * ewma->power; |
| } |
| } |
| } |