Skip to content

Commit

Permalink
optionally add multiple frequency weightings and longer time constants
Browse files Browse the repository at this point in the history
  • Loading branch information
gisogrimm committed Apr 30, 2024
1 parent 25c1274 commit d96eaea
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 22 deletions.
13 changes: 12 additions & 1 deletion libtascar/include/tscconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ namespace tsccfg {
std::string node_get_text(tsccfg::node_t& n, const std::string& child = "");
void node_set_text(tsccfg::node_t& n, const std::string& text);
void node_import_node(tsccfg::node_t& node, const tsccfg::node_t& src);
void node_import_node_before(tsccfg::node_t& node, const tsccfg::node_t& src, const tsccfg::node_t& before);
void node_import_node_before(tsccfg::node_t& node, const tsccfg::node_t& src,
const tsccfg::node_t& before);

// double node_xpath_to_number(tsccfg::node_t&,const std::string& path);

Expand Down Expand Up @@ -227,6 +228,9 @@ namespace TASCAR {
void get_attribute(const std::string& name,
TASCAR::levelmeter::weight_t& value,
const std::string& info);
void get_attribute(const std::string& name,
std::vector<TASCAR::levelmeter::weight_t>& value,
const std::string& info);
void get_attribute(const std::string& name,
std::vector<TASCAR::pos_t>& value,
const std::string& unit, const std::string& info);
Expand Down Expand Up @@ -261,6 +265,8 @@ namespace TASCAR {
const TASCAR::zyx_euler_t& value);
void set_attribute(const std::string& name,
const TASCAR::levelmeter::weight_t& value);
void set_attribute(const std::string& name,
const std::vector<TASCAR::levelmeter::weight_t>& value);
void set_attribute(const std::string& name,
const std::vector<TASCAR::pos_t>& value);
void set_attribute(const std::string& name,
Expand Down Expand Up @@ -395,6 +401,8 @@ void get_attribute_value(const tsccfg::node_t& elem, const std::string& name,
std::vector<int32_t>& value);
void get_attribute_value(const tsccfg::node_t& elem, const std::string& name,
TASCAR::levelmeter::weight_t& value);
void get_attribute_value(const tsccfg::node_t& elem, const std::string& name,
std::vector<TASCAR::levelmeter::weight_t>& value);

void set_attribute_bool(tsccfg::node_t& elem, const std::string& name,
bool value);
Expand Down Expand Up @@ -432,6 +440,9 @@ void set_attribute_value(tsccfg::node_t& elem, const std::string& name,
const std::vector<int32_t>& value);
void set_attribute_value(tsccfg::node_t& elem, const std::string& name,
const TASCAR::levelmeter::weight_t& value);
void set_attribute_value(
tsccfg::node_t& elem, const std::string& name,
const std::vector<TASCAR::levelmeter::weight_t>& value);

#define GET_ATTRIBUTE(x, u, i) get_attribute(#x, x, u, i)
#define GET_ATTRIBUTE_(x) get_attribute(#x, x, "", "undocumented")
Expand Down
66 changes: 64 additions & 2 deletions libtascar/src/tscconfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,22 @@ void TASCAR::xml_element_t::get_attribute(const std::string& name,
set_attribute(name, value);
}

void TASCAR::xml_element_t::get_attribute(
const std::string& name, std::vector<TASCAR::levelmeter::weight_t>& value,
const std::string& info)
{
TASCAR_ASSERT(e);
std::vector<std::string> svalue;
for(const auto& v : value)
svalue.push_back(TASCAR::to_string(v));
node_register_attr(e, name, TASCAR::vecstr2str(svalue), "", info,
"f-weight array");
if(has_attribute(name))
get_attribute_value(e, name, value);
else
set_attribute(name, value);
}

void TASCAR::xml_element_t::set_attribute_bool(const std::string& name,
bool value)
{
Expand Down Expand Up @@ -1469,6 +1485,14 @@ void TASCAR::xml_element_t::set_attribute(
set_attribute_value(e, name, value);
}

void TASCAR::xml_element_t::set_attribute(
const std::string& name,
const std::vector<TASCAR::levelmeter::weight_t>& value)
{
TASCAR_ASSERT(e);
set_attribute_value(e, name, value);
}

std::string TASCAR::env_expand(std::string s)
{
size_t spos;
Expand Down Expand Up @@ -1609,6 +1633,16 @@ void set_attribute_value(tsccfg::node_t& elem, const std::string& name,
tsccfg::node_set_attribute(elem, name, TASCAR::to_string(value));
}

void set_attribute_value(tsccfg::node_t& elem, const std::string& name,
const std::vector<TASCAR::levelmeter::weight_t>& value)
{
TASCAR_ASSERT(elem);
std::vector<std::string> tmp;
for(const auto& v : value)
tmp.push_back(TASCAR::to_string(v));
tsccfg::node_set_attribute(elem, name, TASCAR::vecstr2str(tmp));
}

void set_attribute_value(tsccfg::node_t& elem, const std::string& name,
const std::vector<TASCAR::pos_t>& value)
{
Expand Down Expand Up @@ -1876,6 +1910,32 @@ void get_attribute_value(const tsccfg::node_t& elem, const std::string& name,
std::string("\"."));
}

void get_attribute_value(const tsccfg::node_t& elem, const std::string& name,
std::vector<TASCAR::levelmeter::weight_t>& value)
{
TASCAR_ASSERT(elem);
std::vector<std::string> svalue(
TASCAR::str2vecstr(tsccfg::node_get_attribute_value(elem, name)));
if(svalue.size() == 0)
return;
std::vector<TASCAR::levelmeter::weight_t> tmpvalue;
for(const auto& s : svalue) {
if(s == "Z")
tmpvalue.push_back(TASCAR::levelmeter::Z);
else if(s == "C")
tmpvalue.push_back(TASCAR::levelmeter::C);
else if(s == "A")
tmpvalue.push_back(TASCAR::levelmeter::A);
else if(s == "bandpass")
tmpvalue.push_back(TASCAR::levelmeter::bandpass);
else
throw TASCAR::ErrMsg(std::string("Unsupported weight type \"") + s +
std::string("\" for attribute \"") + name +
std::string("\"."));
}
value = tmpvalue;
}

void get_attribute_value(const tsccfg::node_t& elem, const std::string& name,
std::vector<TASCAR::pos_t>& value)
{
Expand Down Expand Up @@ -2347,13 +2407,15 @@ void tsccfg::node_import_node(tsccfg::node_t& node, const tsccfg::node_t& src)
#endif
}

void tsccfg::node_import_node_before(tsccfg::node_t& node, const tsccfg::node_t& src, const tsccfg::node_t& before)
void tsccfg::node_import_node_before(tsccfg::node_t& node,
const tsccfg::node_t& src,
const tsccfg::node_t& before)
{
#ifdef USEPUGIXML
node.append_copy(src);
#elif defined(USEXERCESXML)
auto impnode(node->getOwnerDocument()->importNode(src, true));
node->insertBefore(impnode,before);
node->insertBefore(impnode, before);
#else
node->import_node(src);
#endif
Expand Down
4 changes: 2 additions & 2 deletions manual/examples/example_profiling.tsc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<sine/>
<pink/>
<filter/>
<level2osc threaded="true" url="osc.udp://localhost:9877/"/>
<level2osc weights="Z A C" tau="1" threaded="true" url="osc.udp://localhost:9877/"/>
<lipsync_paper threaded="true" path="/lipsyncp" energypath="/energyp" strmsg="" url="osc.udp://localhost:9877/"/>
<lipsync threaded="true" path="/lipsync" energypath="/energy" strmsg="" url="osc.udp://localhost:9877/"/>
<timestamp path="/ts2"/>
Expand All @@ -20,7 +20,7 @@
<pos2osc pattern="/*/*"/>
<datalogging>
<osc path="/prof" size="8"/>
<osc path="/level" size="2" ignorefirst="true"/>
<osc path="/level" size="4" ignorefirst="true"/>
<osc path="/lipsyncp" size="3"/>
<osc path="/lipsync" size="3"/>
<osc path="/energyp" size="5"/>
Expand Down
57 changes: 40 additions & 17 deletions plugins/src/tascar_ap_level2osc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "audioplugin.h"
#include "errorhandling.h"
#include "levelmeter.h"
#include <atomic>
#include <chrono>
#include <condition_variable>
Expand All @@ -45,6 +46,8 @@ class level2osc_t : public TASCAR::audioplugin_base_t {
bool threaded = true;
bool sendwhilestopped = false;
uint32_t skip = 0;
float tau = 0;
std::vector<TASCAR::levelmeter::weight_t> weights;
std::string url = "osc.udp://localhost:9999/";
std::string path = "/level";
// derived variables:
Expand All @@ -59,16 +62,23 @@ class level2osc_t : public TASCAR::audioplugin_base_t {
std::mutex mtx;
std::condition_variable cond;
std::atomic_bool has_data = false;
std::vector<TASCAR::levelmeter_t> sigcopy;
double currenttime = 0;
};

level2osc_t::level2osc_t(const TASCAR::audioplugin_cfg_t& cfg)
: audioplugin_base_t(cfg)
{
weights.push_back(TASCAR::levelmeter::Z);
GET_ATTRIBUTE_BOOL(sendwhilestopped, "Send also when transport is stopped");
GET_ATTRIBUTE(skip, "", "Skip frames");
GET_ATTRIBUTE_NOUNIT(weights, "Level meter weights");
if(weights.size() == 0)
throw TASCAR::ErrMsg("At least one frequency weight is required.");
GET_ATTRIBUTE(url, "", "Target URL");
GET_ATTRIBUTE(path, "", "Target path");
GET_ATTRIBUTE_BOOL(threaded, "Use additional thread for sending data");
GET_ATTRIBUTE(tau, "s", "Leq duration, or 0 to use block size");
std::string mode("dbspl");
GET_ATTRIBUTE(mode, "", "Level mode [dbspl|rms|max]");
if(mode == "dbspl")
Expand All @@ -90,6 +100,21 @@ void level2osc_t::sendthread()
while(run_thread) {
cond.wait_for(lk, 100ms);
if(has_data) {
// pack data:
oscmsgargv[0]->f = currenttime;
for(size_t ch = 0; ch < sigcopy.size(); ++ch) {
switch(imode) {
case dbspl:
oscmsgargv[ch + 1]->f = sigcopy[ch].spldb();
break;
case rms:
oscmsgargv[ch + 1]->f = sigcopy[ch].rms();
break;
case max:
oscmsgargv[ch + 1]->f = sigcopy[ch].maxabs();
break;
}
}
lo_send_message(lo_addr, path.c_str(), msg);
has_data = false;
}
Expand All @@ -99,18 +124,27 @@ void level2osc_t::sendthread()
void level2osc_t::configure()
{
audioplugin_base_t::configure();
sigcopy.clear();
msg = lo_message_new();
// time:
lo_message_add_float(msg, 0);
float tau_ = tau;
if(tau_ == 0)
tau_ = t_fragment;
// levels:
for(uint32_t k = 0; k < n_channels; ++k)
lo_message_add_float(msg, 0);
for(size_t kweight = 0; kweight < weights.size(); ++kweight)
for(uint32_t k = 0; k < n_channels; ++k) {
lo_message_add_float(msg, 0);
sigcopy.push_back(TASCAR::levelmeter_t(f_sample, tau_, weights[kweight]));
// sigcopy.back().set_weight(weights[kweight]);
}
oscmsgargv = lo_message_get_argv(msg);
}

void level2osc_t::release()
{
lo_message_free(msg);
sigcopy.clear();
audioplugin_base_t::release();
}

Expand All @@ -131,27 +165,16 @@ void level2osc_t::ap_process(std::vector<TASCAR::wave_t>& chunk,
"Programming error (invalid channel number, expected " +
TASCAR::to_string(n_channels) + ", got " +
std::to_string(chunk.size()) + ").");
for(size_t kweight = 0; kweight < weights.size(); ++kweight)
for(uint32_t k = 0; k < n_channels; ++k)
sigcopy[kweight * n_channels + k].update(chunk[k]);
if(tp.rolling || sendwhilestopped) {
if(skipcnt) {
skipcnt--;
} else {
// data will be sent in extra thread:
if(mtx.try_lock()) {
// pack data:
oscmsgargv[0]->f = tp.object_time_seconds;
for(uint32_t ch = 0; ch < n_channels; ++ch) {
switch(imode) {
case dbspl:
oscmsgargv[ch + 1]->f = chunk[ch].spldb();
break;
case rms:
oscmsgargv[ch + 1]->f = chunk[ch].rms();
break;
case max:
oscmsgargv[ch + 1]->f = chunk[ch].maxabs();
break;
}
}
currenttime = tp.object_time_seconds;
has_data = true;
mtx.unlock();
if(threaded)
Expand Down

0 comments on commit d96eaea

Please sign in to comment.