blob: fab4644f4bca4fb87732dd63004a11d647b87231 [file] [log] [blame]
/*
* BandwidthDetector.cpp
*
* Copyright 2021 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
* www.ehima.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "BandwidthDetector.hpp"
#include <cmath>
namespace Lc3Enc {
static const uint8_t I_bw_start_table[5][4] = {
{53, 0, 0, 0}, // N_bw=1
{47, 59, 0, 0}, // N_bw=2
{44, 54, 60, 0}, // N_bw=3
{41, 51, 57, 61} // N_bw=4
};
static const uint8_t I_bw_stop_table[5][4] = {
{63, 0, 0, 0}, // N_bw=1
{56, 63, 0, 0}, // N_bw=2
{52, 59, 63, 0}, // N_bw=3
{49, 55, 60, 63} // N_bw=4
};
static const uint8_t I_bw_start_table_7p5ms[5][4] = {
{51, 0, 0, 0}, // N_bw=1
{45, 58, 0, 0}, // N_bw=2
{42, 53, 60, 0}, // N_bw=3
{40, 51, 57, 61} // N_bw=4
};
static const uint8_t I_bw_stop_table_7p5ms[5][4] = {
{63, 0, 0, 0}, // N_bw=1
{55, 63, 0, 0}, // N_bw=2
{51, 58, 63, 0}, // N_bw=3
{48, 55, 60, 63} // N_bw=4
};
static const uint8_t nbits_bw_table[5] = {
0, 1, 2, 2, 3}; // see 3.4.2.4 Bandwidth interpretation (d09r02_F2F)
static const uint8_t T_Q[4] = {20, 10, 10, 10};
static const uint8_t T_C[4] = {15, 23, 20, 20};
static const uint8_t L_10ms[4] = {4, 4, 3, 1};
static const uint8_t L_7p5ms[4] = {4, 4, 3, 2};
BandwidthDetector::BandwidthDetector(const Lc3Config& lc3Config_)
: lc3Config(lc3Config_),
N_bw(calc_N_bw(lc3Config.Fs_ind)),
nbits_bw(nbits_bw_table[calc_N_bw(lc3Config.Fs_ind)]),
P_bw(0) {
if (N_bw != 0) {
I_bw_start = (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms)
? I_bw_start_table[N_bw - 1]
: I_bw_start_table_7p5ms[N_bw - 1];
I_bw_stop = (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms)
? I_bw_stop_table[N_bw - 1]
: I_bw_stop_table_7p5ms[N_bw - 1];
}
L = (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? L_10ms : L_7p5ms;
}
BandwidthDetector::~BandwidthDetector() {}
uint8_t BandwidthDetector::calc_N_bw(uint8_t fs_ind) {
// see Table 3.5: Parameter table bandwidth detector
// 3.3.5.2 Parameters (d09r02_F2F)
return fs_ind;
}
void BandwidthDetector::run(const double* const E_B) {
if (0 == N_bw) {
return;
}
// 3.3.5.1 Algorithm (first stage) (d09r02_F2F)
// Note: it seems like there is no need to compute
// the entire specified sequence of flahs F_Q[k]
// when we start searching for an active band
// from the highest fequency band to lower bands
uint8_t bw_0 = 0;
for (uint8_t k = N_bw - 1; k < N_bw; k--) // stops when 0-- goes to 255
{
uint8_t width = I_bw_stop[k] - I_bw_start[k] + 1;
double Q = 0.0;
for (uint8_t n = I_bw_start[k]; n <= I_bw_stop[k]; n++) {
Q += E_B[n] / width;
}
if (Q >= T_Q[k]) {
// activity detected (not quiet) -> this is the band index to be selected
bw_0 = k + 1;
break;
}
}
// 3.3.5.1 Algorithm (second stage) (d09r02_F2F)
if (N_bw == bw_0) {
P_bw = bw_0;
} else {
double Cmax = 0;
for (uint8_t n = I_bw_start[bw_0] - L[bw_0] + 1; n <= I_bw_start[bw_0] + 1;
n++) {
double C = 10 * log10(E_B[n - L[bw_0]] / E_B[n]);
if (C > Cmax) {
Cmax = C;
}
}
if (Cmax > T_C[bw_0]) {
P_bw = bw_0;
} else {
P_bw = N_bw;
}
}
}
void BandwidthDetector::registerDatapoints(DatapointContainer* datapoints) {
if (nullptr != datapoints) {
datapoints->addDatapoint("P_bw", &P_bw, sizeof(P_bw));
}
}
} // namespace Lc3Enc