1 /* Copyright 2020 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include "ewma_power.h"
7 #include "math.h"
8
9 /* One sample per 1ms. */
10 #define EWMA_SAMPLE_RATE 1000
11
12 /* Smooth factor for EWMA, 1 - expf(-1.0/(rate * 0.01))
13 * where the 0.01 corresponds to 10ms interval that is chosen and
14 * being used in Chrome for a long time.
15 * Here the |rate| is set to the down sampled EWMA_SAMPLE_RATE and
16 * whenever it changes the calculated |smooth_factor| should be updated
17 * accordingly.
18 */
19 const static float smooth_factor = 0.095;
20
ewma_power_disable(struct ewma_power * ewma)21 void ewma_power_disable(struct ewma_power *ewma)
22 {
23 ewma->enabled = 0;
24 }
25
ewma_power_init(struct ewma_power * ewma,unsigned int rate)26 void ewma_power_init(struct ewma_power *ewma, unsigned int rate)
27 {
28 ewma->enabled = 1;
29 ewma->power_set = 0;
30 ewma->step_fr = rate / EWMA_SAMPLE_RATE;
31 }
32
ewma_power_calculate(struct ewma_power * ewma,const int16_t * buf,unsigned int channels,unsigned int size)33 void ewma_power_calculate(struct ewma_power *ewma, const int16_t *buf,
34 unsigned int channels, unsigned int size)
35 {
36 int i, ch;
37 float power, f;
38
39 if (!ewma->enabled)
40 return;
41 for (i = 0; i < size; i += ewma->step_fr * channels) {
42 power = 0.0f;
43 for (ch = 0; ch < channels; ch++) {
44 f = buf[i + ch] / 32768.0f;
45 power += f * f / channels;
46 }
47 if (!ewma->power_set) {
48 ewma->power = power;
49 ewma->power_set = 1;
50 } else {
51 ewma->power = smooth_factor * power +
52 (1 - smooth_factor) * ewma->power;
53 }
54 }
55 }
56
ewma_power_calculate_area(struct ewma_power * ewma,const int16_t * buf,struct cras_audio_area * area,unsigned int size)57 void ewma_power_calculate_area(struct ewma_power *ewma, const int16_t *buf,
58 struct cras_audio_area *area, unsigned int size)
59 {
60 int i, ch;
61 float power, f;
62
63 if (!ewma->enabled)
64 return;
65 for (i = 0; i < size; i += ewma->step_fr * area->num_channels) {
66 power = 0.0f;
67 for (ch = 0; ch < area->num_channels; ch++) {
68 if (area->channels[ch].ch_set == 0)
69 continue;
70 f = buf[i + ch] / 32768.0f;
71 power += f * f / area->num_channels;
72 }
73 if (!ewma->power_set) {
74 ewma->power = power;
75 ewma->power_set = 1;
76 } else {
77 ewma->power = smooth_factor * power +
78 (1 - smooth_factor) * ewma->power;
79 }
80 }
81 }
82