unplugged-vendor/system/bt/embdrv/lc3/Encoder/AttackDetector.cpp

124 lines
4.1 KiB
C++

/*
* AttackDetector.cpp
*
* Copyright 2019 HIMSA II K/S - www.himsa.dk. 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 "AttackDetector.hpp"
#include <cmath>
namespace Lc3Enc
{
AttackDetector::AttackDetector(const Lc3Config& lc3Config_) :
lc3Config(lc3Config_),
M_F( (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 160 : 120), // 16*N_ms
F_att(0),
E_att_last(0),
A_att_last(0),
P_att_last(-1)
{
// make sure these states are initially zero as demanded by the specification
x_att_last[0] = 0;
x_att_last[1] = 0;
}
AttackDetector::~AttackDetector()
{
}
void AttackDetector::run(const int16_t* const x_s, uint16_t nbytes)
{
// 3.3.6.1 Overview (d09r06_FhG)
// -> attack detection active only for higher bitrates and fs>=32000; otherwise defaults are set
F_att = 0;
if ( lc3Config.Fs < 32000 )
{
return;
}
bool isActive =
( (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) && (lc3Config.Fs==32000) && (nbytes>80) ) ||
( (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) && (lc3Config.Fs>=44100) && (nbytes>=100) ) ||
( (lc3Config.N_ms == Lc3Config::FrameDuration::d7p5ms) && (lc3Config.Fs==32000) && (nbytes>=61) && (nbytes<150) ) ||
( (lc3Config.N_ms == Lc3Config::FrameDuration::d7p5ms) && (lc3Config.Fs>=44100) && (nbytes>=75) && (nbytes<150) );
if ( !isActive )
{
// Note: in bitrate switching situations we have to set proper states
E_att_last = 0;
A_att_last = 0;
P_att_last = -1;
return;
}
// 3.3.6.2 Downsampling and filtering of input signal (d09r02_F2F)
// Note: the following section might be converted to int32 instead
// of double computation (maybe something for optimization)
double x_att_extended[M_F+2];
x_att_extended[0] = x_att_last[0];
x_att_extended[1] = x_att_last[1];
double* x_att = &x_att_extended[2];
for (uint8_t n=0; n < M_F; n++) // downsampling
{
x_att[n] = 0;
for (uint8_t m=0; m < lc3Config.NF/M_F; m++)
{
x_att[n] += x_s[ lc3Config.NF/M_F*n + m ];
}
}
x_att_last[0] = x_att[M_F-2];
x_att_last[1] = x_att[M_F-1];
double* x_hp = x_att_extended; // just for improve readability
for (uint8_t n=0; n < M_F; n++) // highpass-filtering (in-place!)
{
x_hp[n] = 0.375*x_att[n] - 0.5*x_att[n-1] + 0.125*x_att[n-2];
}
// 3.3.6.3 Energy calculation & 3.3.6.4 Attack detection (d09r06_FhG)
int8_t P_att = -1;
const uint8_t N_blocks = (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 4 : 3; // N_ms/2.5
for (uint8_t n=0; n < N_blocks; n++)
{
double E_att = 0;
for (uint8_t l=40*n; l <= (40*n+39); l++)
{
E_att += x_hp[l]*x_hp[l];
}
double A_att = (0.25*A_att_last > E_att_last) ? 0.25*A_att_last : E_att_last;
if (E_att > 8.5*A_att)
{
// attack detected
P_att = n;
}
E_att_last = E_att;
A_att_last = A_att;
}
const uint8_t T_att = (lc3Config.N_ms == Lc3Config::FrameDuration::d10ms) ? 2 : 1; // floor(N_blocks/2)
F_att = (P_att >= 0) || (P_att_last >= T_att);
P_att_last = P_att; // prepare next frame
}
void AttackDetector::registerDatapoints(DatapointContainer* datapoints)
{
if (nullptr != datapoints)
{
datapoints->addDatapoint( "F_att", &F_att, sizeof(F_att) );
}
}
}//namespace Lc3Enc