2#include "debugtrace.hpp"
12using rte = std::runtime_error;
15SLM::SLM(
const d fs,
const d Lref,
const us downsampling_fac,
const d tau,
16 std::unique_ptr<Filter> pre_filter,
17 std::vector<std::unique_ptr<Filter>> bandpass)
18 : _pre_filter(std::move(pre_filter)), _bandpass(std::move(bandpass)),
19 _alpha(exp(-1 / (fs * tau))),
20 _sp_storage(_bandpass.size(), arma::fill::zeros),
25 downsampling_fac(downsampling_fac),
28 Pm(_bandpass.size(), arma::fill::zeros),
31 Pmax(_bandpass.size(), arma::fill::zeros),
34 Ppeak(_bandpass.size(), arma::fill::zeros)
38 DEBUGTRACE_PRINT(_alpha);
41 throw rte(
"Invalid reference level");
44 throw rte(
"Invalid time constant for Single pole lowpass filter");
47 throw rte(
"Invalid sampling frequency");
61 std::vector<unique_ptr<Filter>> bf;
62 for (
us colno = 0; colno < coefs.n_cols; colno++) {
63 bf.emplace_back(std::make_unique<SeriesBiquad>(coefs.col(colno)));
69 throw rte(
"Invalid sampling frequency");
77 return std::max((
us)1,
static_cast<us>(fs / fs_slm));
84 const d tau,
const vd &pre_filter_coefs,
85 const dmat &bandpass_coefs) {
88 return SLM(fs, Lref, downsampling_fac, tau,
89 std::make_unique<SeriesBiquad>(pre_filter_coefs),
93 const d tau,
const dmat &bandpass_coefs) {
97 return SLM(fs, Lref, downsampling_fac, tau,
103vd SLM::run_single(
vd work,
const us i) {
106 _bandpass[i]->filter(work);
115 Ppeak(i) = std::max(
Ppeak(i), arma::max(work));
122 d cur_storage = _sp_storage(i);
124 for (
us j = 0; j < work.n_rows; j++) {
126 Pm(i) = (
Pm(i) *
static_cast<d
>(N_local) + work(j)) /
127 (
static_cast<d
>(N_local) + 1);
131 cur_storage = _alpha * cur_storage + (1 - _alpha) * work(j);
134 work(j) = cur_storage;
138 _sp_storage(i) = cur_storage;
140 Pmax(i) = std::max(
Pmax(i), arma::max(work));
143 work = 10 * arma::log10((work + arma::datum::eps) / Lrefsq);
151 vd input = input_orig;
155 _pre_filter->filter(input);
159 dmat res(input.n_rows, _bandpass.size());
163#pragma omp parallel for
164 for (
us i = 0; i < _bandpass.size(); i++) {
165 res.col(i) = run_single(input, i);
177 if (downsampling_fac > 1) {
180 while (cur_offset < res.n_rows) {
181 res_ds.insert_rows(rowno, res.row(cur_offset));
184 cur_offset += downsampling_fac;
186 cur_offset -= res.n_rows;
197 for (
auto &f : _bandpass) {
201 _pre_filter->reset();
Sound Level Meter implementation that gives a result for each channel. A channel is the result of a f...
vd Pmax
Public storage for the maximum signal power, after single pole low-pass filter.
vd Pm
Public storage for the mean of the square of the signal.
static us suggestedDownSamplingFac(const d fs, const d tw)
Comput a 'suggested' downsampling factor, i.e. a lower frame rate at which sound level meter values a...
dmat run(const vd &input)
Run the sound level meter on given input data. Return downsampled level data for each filterbank chan...
void reset()
Reset state related to samples acquired. All filters reset to zero. Start again from no history.
vd Ppeak
Storage for maximum computed signal power so far.
static SLM fromBiquads(const d fs, const d Lref, const us downsampling_fac, const d tau, const vd &pre_filter_coefs, const dmat &bandpass_coefs)
Convenience function to create a Sound Level meter from Biquad filters only.
SLM(const d fs, const d Lref, const us downsampling_fac, const d tau, std::unique_ptr< Filter > pre_filter, std::vector< std::unique_ptr< Filter > > bandpass)
Initialize a Sound Level Meter.
std::vector< unique_ptr< Filter > > createBandPass(const dmat &coefs)
Create set bandpass filters from filter coefficients.
size_t us
We often use boolean values.