diff options
author | Alfred E. Heggestad <alfred.heggestad@gmail.com> | 2017-04-27 20:30:31 +0200 |
---|---|---|
committer | Alfred E. Heggestad <alfred.heggestad@gmail.com> | 2017-04-27 20:30:31 +0200 |
commit | ea12293e0a6764fb4655420de8e906bd42d90efd (patch) | |
tree | 70629399c3cf07a520d40a075705c37e3d55a1d0 | |
parent | 036030c23b1fac6bda68bdd9406ffca5c7539759 (diff) |
aulevel: calculate audio levels in dBov
-rw-r--r-- | include/baresip.h | 12 | ||||
-rw-r--r-- | src/aulevel.c | 85 | ||||
-rw-r--r-- | src/srcs.mk | 1 | ||||
-rw-r--r-- | test/aulevel.c | 61 | ||||
-rw-r--r-- | test/main.c | 1 | ||||
-rw-r--r-- | test/srcs.mk | 1 | ||||
-rw-r--r-- | test/test.h | 1 |
7 files changed, 162 insertions, 0 deletions
diff --git a/include/baresip.h b/include/baresip.h index f00b5c9..5087296 100644 --- a/include/baresip.h +++ b/include/baresip.h @@ -65,6 +65,18 @@ const char *account_stun_host(const struct account *acc); /* + * Audio-level + */ + + +#define AULEVEL_MIN (-96.0) +#define AULEVEL_MAX (0.0) + + +double aulevel_calc_dbov(const int16_t *sampv, size_t sampc); + + +/* * Call */ diff --git a/src/aulevel.c b/src/aulevel.c new file mode 100644 index 0000000..bc9a27a --- /dev/null +++ b/src/aulevel.c @@ -0,0 +1,85 @@ +/** + * @file src/aulevel.c Audio level + * + * Copyright (C) 2017 Creytiv.com + */ + +#include <math.h> +#include <re.h> +#include <baresip.h> +#include "core.h" + + +/** + * Generic routine to calculate RMS (Root-Mean-Square) from + * a set of signed 16-bit values + * + * \verbatim + + .--------------- + | N-1 + | ----. + | \ + | \ 2 + | | s[n] + | / + | / + _ | ----' + \ | n=0 + \ | ------------ + \| N + + \endverbatim + * + * @param data Array of signed 16-bit values + * @param len Number of values + * + * @return RMS value from 0 to 32768 + */ +static double calc_rms(const int16_t *data, size_t len) +{ + double sum = 0; + size_t i; + + if (!data || !len) + return .0; + + for (i = 0; i < len; i++) { + const double sample = data[i]; + + sum += sample * sample; + } + + return sqrt(sum / (double)len); +} + + +/** + * Calculate the audio level in dBov from a set of audio samples. + * dBov is the level, in decibels, relative to the overload point + * of the system + * + * @param sampv Audio samples + * @param sampc Number of audio samples + * + * @return Audio level expressed in dBov + */ +double aulevel_calc_dbov(const int16_t *sampv, size_t sampc) +{ + static const double peak = 32767.0; + double rms, dbov; + + if (!sampv || !sampc) + return AULEVEL_MIN; + + rms = calc_rms(sampv, sampc) / peak; + + dbov = 20 * log10(rms); + + if (dbov < AULEVEL_MIN) + dbov = AULEVEL_MIN; + else if (dbov > AULEVEL_MAX) + dbov = AULEVEL_MAX; + + return dbov; +} diff --git a/src/srcs.mk b/src/srcs.mk index c538600..cdb2a26 100644 --- a/src/srcs.mk +++ b/src/srcs.mk @@ -8,6 +8,7 @@ SRCS += account.c SRCS += aucodec.c SRCS += audio.c SRCS += aufilt.c +SRCS += aulevel.c SRCS += auplay.c SRCS += ausrc.c SRCS += baresip.c diff --git a/test/aulevel.c b/test/aulevel.c new file mode 100644 index 0000000..6d083f6 --- /dev/null +++ b/test/aulevel.c @@ -0,0 +1,61 @@ +/** + * @file test/aulevel.c Baresip selftest -- audio levels + * + * Copyright (C) 2010 - 2017 Creytiv.com + */ + +#include <re.h> +#include <baresip.h> +#include "test.h" + + +#define DEBUG_MODULE "aulevel" +#define DEBUG_LEVEL 5 +#include <re_dbg.h> + + +#define PREC .6 + + +int test_aulevel(void) +{ + static const struct { + int16_t sampv[2]; + double level; + } testv[] = { + + { { 0, -0}, -96.0 }, + { { 0, 1}, -93.0 }, + { { 1, -1}, -90.0 }, + { { 2, -2}, -84.0 }, + { { 4, -4}, -78.0 }, + { { 8, -8}, -72.0 }, + { { 16, -16}, -66.0 }, + { { 32, -32}, -60.0 }, + { { 64, -64}, -54.0 }, + { { 128, -128}, -48.0 }, + { { 256, -256}, -42.0 }, + { { 512, -512}, -36.0 }, + { { 1024, -1024}, -30.0 }, + { { 2048, -2048}, -24.0 }, + { { 4096, -4096}, -18.0 }, + { { 8192, -8192}, -12.0 }, + { {16384, -16384}, -6.0 }, + { {32767, -32768}, 0.0 }, + }; + size_t i; + int err = 0; + + for (i=0; i<ARRAY_SIZE(testv); i++) { + + double level; + + level = aulevel_calc_dbov(testv[i].sampv, + ARRAY_SIZE(testv[i].sampv)); + + ASSERT_DOUBLE_EQ(testv[i].level, level, PREC); + } + + out: + return err; +} diff --git a/test/main.c b/test/main.c index 125f1ec..f443dcb 100644 --- a/test/main.c +++ b/test/main.c @@ -23,6 +23,7 @@ struct test { static const struct test tests[] = { TEST(test_account), + TEST(test_aulevel), TEST(test_call_af_mismatch), TEST(test_call_answer), TEST(test_call_answer_hangup_a), diff --git a/test/srcs.mk b/test/srcs.mk index 3c481ac..b3a2637 100644 --- a/test/srcs.mk +++ b/test/srcs.mk @@ -9,6 +9,7 @@ # Test-cases: # TEST_SRCS += account.c +TEST_SRCS += aulevel.c TEST_SRCS += call.c TEST_SRCS += cmd.c TEST_SRCS += contact.c diff --git a/test/test.h b/test/test.h index 3a19ec1..a68d61d 100644 --- a/test/test.h +++ b/test/test.h @@ -178,6 +178,7 @@ int mock_vidisp_register(struct vidisp **vidispp); /* test cases */ int test_account(void); +int test_aulevel(void); int test_cmd(void); int test_cmd_long(void); int test_contact(void); |