From f2f7e1543dea055e42ab5295189df2f117196f2e Mon Sep 17 00:00:00 2001 From: Giso Grimm Date: Wed, 12 Jun 2024 08:57:07 +0200 Subject: [PATCH] use individual mute states in each sound --- libtascar/include/scene.h | 7 +++- libtascar/src/osc_scene.cc | 2 + libtascar/src/scene.cc | 6 ++- plugins/src/tascarmod_midictl.cc | 42 +++++++++++++++------ plugins/src/tascarmod_touchosc.cc | 62 ++++++++++++++++++++----------- 5 files changed, 85 insertions(+), 34 deletions(-) diff --git a/libtascar/include/scene.h b/libtascar/include/scene.h index e551dc95..b13eb50a 100644 --- a/libtascar/include/scene.h +++ b/libtascar/include/scene.h @@ -267,6 +267,7 @@ namespace TASCAR { private: TASCAR::Acousticmodel::diffuse_t* source; + public: plugin_processor_t plugins; }; @@ -308,6 +309,8 @@ namespace TASCAR { void add_meter(TASCAR::levelmeter_t*); float read_meter(); void validate_attributes(std::string& msg) const; + void set_mute(bool m) { b_mute = m; }; + bool get_mute() const { return b_mute; }; public: src_object_t* parent; @@ -315,10 +318,11 @@ namespace TASCAR { pos_t local_position; zyx_euler_t local_orientation; pos_t global_position; + bool b_mute = false; private: double chaindist; - double gain_; + float gain_; std::vector meter; }; @@ -426,6 +430,7 @@ namespace TASCAR { private: uint32_t outputlayers; TASCAR::Acousticmodel::diffuse_t* source; + public: plugin_processor_t plugins; }; diff --git a/libtascar/src/osc_scene.cc b/libtascar/src/osc_scene.cc index bb221a20..38bd74df 100644 --- a/libtascar/src/osc_scene.cc +++ b/libtascar/src/osc_scene.cc @@ -302,6 +302,8 @@ void osc_scene_t::add_sound_methods(TASCAR::osc_server_t* srv, "Number representing the layers. Each layer is represented by " "a bit, i.e., for layers 1+3 use 10"); srv->add_float("/size", &(s->size), "", "Object size in meter"); + srv->add_bool("/mute", &(s->b_mute), + "Mute state of individual sound, independent of parent"); s->plugins.add_variables(srv); srv->add_pos("/pos", &(s->local_position), "", "local position of sound vertex in meters"); diff --git a/libtascar/src/scene.cc b/libtascar/src/scene.cc index 4278e0c3..891b6eac 100644 --- a/libtascar/src/scene.cc +++ b/libtascar/src/scene.cc @@ -1326,13 +1326,17 @@ void sound_t::add_meter(TASCAR::levelmeter_t* m) void sound_t::apply_gain() { - double dg((get_gain() - gain_) * t_inc); + float newgain = get_gain(); + if( b_mute ) + newgain = 0.0f; + float dg((newgain - gain_) * t_inc); uint32_t channels(inchannels.size()); for(uint32_t k = 0; k < inchannels[0].n; ++k) { gain_ += dg; for(uint32_t c = 0; c < channels; ++c) inchannels[c].d[k] *= gain_; } + gain_ = newgain; for(uint32_t k = 0; k < n_channels; ++k) meter[k]->update(inchannels[k]); } diff --git a/plugins/src/tascarmod_midictl.cc b/plugins/src/tascarmod_midictl.cc index 86a4084c..eb16cc77 100644 --- a/plugins/src/tascarmod_midictl.cc +++ b/plugins/src/tascarmod_midictl.cc @@ -36,18 +36,23 @@ class midictl_vars_t : public TASCAR::module_base_t { std::vector pattern; double min; double max; + bool mutesounds = true; }; midictl_vars_t::midictl_vars_t(const TASCAR::module_cfg_t& cfg) : module_base_t(cfg), dumpmsg(false), min(0), max(1) { - GET_ATTRIBUTE_BOOL_(dumpmsg); + GET_ATTRIBUTE_BOOL(dumpmsg, "Show unused messages in concole"); GET_ATTRIBUTE_(name); - GET_ATTRIBUTE_(connect); - GET_ATTRIBUTE_(controllers); - GET_ATTRIBUTE_(pattern); + GET_ATTRIBUTE(connect, "", "ALSA midi port connection, e.g., BCF2000:0"); + GET_ATTRIBUTE( + controllers, "", + "MIDI CC controllers in form channel/param, both starting at zero"); + GET_ATTRIBUTE(pattern, "", "TASCAR controllers"); GET_ATTRIBUTE_(min); GET_ATTRIBUTE_(max); + GET_ATTRIBUTE_BOOL(mutesounds, + "Mute individual sounds instead of parent sources"); } class midictl_t : public midictl_vars_t, public TASCAR::midi_ctl_t { @@ -64,6 +69,7 @@ class midictl_t : public midictl_vars_t, public TASCAR::midi_ctl_t { std::vector values; std::vector ports; std::vector routes; + std::vector sounds; std::thread srv; bool run_service; bool upload; @@ -101,16 +107,19 @@ void midictl_t::configure() { ports.clear(); routes.clear(); + sounds.clear(); if(session) ports = session->find_audio_ports(pattern); - for(auto it = ports.begin(); it != ports.end(); ++it) { - TASCAR::Scene::route_t* r(dynamic_cast(*it)); + for(auto& it : ports) { + TASCAR::Scene::route_t* r(dynamic_cast(it)); + TASCAR::Scene::sound_t* s = NULL; if(!r) { - TASCAR::Scene::sound_t* s(dynamic_cast(*it)); + s = dynamic_cast(it); if(s) r = dynamic_cast(s->parent); } routes.push_back(r); + sounds.push_back(s); } start_service(); } @@ -152,8 +161,14 @@ void midictl_t::send_service() } // mute: uint32_t k1 = k + ports.size(); - if(routes[k] && (k1 < controllers_.size())) { - uint8_t v(127 * routes[k]->get_mute()); + if((k1 < controllers_.size())) { + uint8_t v = 0; + if(mutesounds && sounds[k]) { + v = 127 * sounds[k]->get_mute(); + } else { + if(routes[k]) + v = 127 * routes[k]->get_mute(); + } if((v != values[k1]) || upload) { values[k1] = v; int channel(controllers_[k1] >> 8); @@ -184,9 +199,14 @@ void midictl_t::emit_event(int channel, int param, int value) } else { uint32_t k1(k - ports.size()); if(k1 < routes.size()) { - if(routes[k1]) { + if(mutesounds && sounds[k1]) { values[k] = value; - routes[k1]->set_mute(value > 0); + sounds[k1]->set_mute(value > 0); + } else { + if(routes[k1]) { + values[k] = value; + routes[k1]->set_mute(value > 0); + } } } } diff --git a/plugins/src/tascarmod_touchosc.cc b/plugins/src/tascarmod_touchosc.cc index 4b157a1e..2858e004 100644 --- a/plugins/src/tascarmod_touchosc.cc +++ b/plugins/src/tascarmod_touchosc.cc @@ -95,7 +95,7 @@ std::string col2colname(TASCAR::Scene::rgb_color_t col) class connection_t { public: connection_t(const std::string& host, uint32_t port, uint32_t channels, - bool htmlcolors_); + bool htmlcolors_, bool mutesounds_); void uploadsession(TASCAR::session_t* session, std::vector& routeports); void updatesession(TASCAR::session_t* session, @@ -105,8 +105,8 @@ class connection_t { std::vector& routeports, uint32_t channel, float val); void setmutesession(TASCAR::session_t* session, - std::vector& routeports, - uint32_t channel, bool val); + std::vector& routeports, + uint32_t channel, bool val); ~connection_t(); uint32_t scene; @@ -118,17 +118,20 @@ class connection_t { std::vector levels; std::vector mutestates; bool htmlcolors; + bool mutesounds; }; connection_t::connection_t(const std::string& host, uint32_t port, - uint32_t channels_, bool htmlcolors_) - : scene(0), channels(channels_), htmlcolors(htmlcolors_) + uint32_t channels_, bool htmlcolors_, + bool mutesounds_) + : scene(0), channels(channels_), htmlcolors(htmlcolors_), + mutesounds(mutesounds_) { vals.resize(channels); levels.resize(channels); mutestates.resize(channels); char ctmp[32]; - SNPRINTF(ctmp,32,"%d", port); + SNPRINTF(ctmp, 32, "%d", port); target = lo_address_new(host.c_str(), ctmp); if(!target) throw TASCAR::ErrMsg("Unable to create target adress \"" + host + "\"."); @@ -167,8 +170,12 @@ void connection_t::uploadsession( lo_send(target, cfader, "f", v); lo_send(target, clabel, "s", it->get_fullname().c_str()); lo_send(target, clevel, "f", l); - if( it->parent ) - lo_send(target, cmute, "i", it->parent->get_mute()); + if(mutesounds) { + lo_send(target, cmute, "i", it->get_mute()); + } else { + if(it->parent) + lo_send(target, cmute, "i", it->parent->get_mute()); + } std::string col; if(!htmlcolors) col = col2colname(it->get_color()); @@ -329,9 +336,13 @@ void connection_t::updatesession( levels[ch] = l; } bool vb = false; - if( it->parent ) - vb = it->parent->get_mute(); - if(force || (mutestates[ch] != vb)){ + if(mutesounds) { + vb = it->get_mute(); + } else { + if(it->parent) + vb = it->parent->get_mute(); + } + if(force || (mutestates[ch] != vb)) { lo_send(target, cmute, "i", vb); } mutestates[ch] = vb; @@ -359,7 +370,7 @@ void connection_t::updatesession( } bool vb = false; vb = it->get_mute(); - if(force || (mutestates[ch] != vb)){ + if(force || (mutestates[ch] != vb)) { lo_send(target, cmute, "i", vb); } mutestates[ch] = vb; @@ -387,7 +398,7 @@ void connection_t::updatesession( } bool vb = false; vb = it->get_mute(); - if(force || (mutestates[ch] != vb)){ + if(force || (mutestates[ch] != vb)) { lo_send(target, cmute, "i", vb); } mutestates[ch] = vb; @@ -419,7 +430,7 @@ void connection_t::updatesession( } bool vb = false; vb = scenerp->get_mute(); - if(force || (mutestates[ch] != vb)){ + if(force || (mutestates[ch] != vb)) { lo_send(target, cmute, "i", vb); } mutestates[ch] = vb; @@ -500,8 +511,12 @@ void connection_t::setmutesession( for(auto it : session->scenes[scene]->sounds) { if(ch < channels) { if(ch == channel) { - if( it->parent ) - it->parent->set_mute(val); + if(mutesounds) { + it->set_mute(val); + } else { + if(it->parent) + it->parent->set_mute(val); + } return; } ++ch; @@ -555,7 +570,7 @@ class touchosc_t : public TASCAR::module_base_t, TASCAR::service_t { static int osc_setfader(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data); static int osc_setmute(const char* path, const char* types, lo_arg** argv, - int argc, lo_message msg, void* user_data); + int argc, lo_message msg, void* user_data); static int osc_sceneinc(const char* path, const char* types, lo_arg** argv, int argc, lo_message msg, void* user_data); static int osc_scenedec(const char* path, const char* types, lo_arg** argv, @@ -569,6 +584,7 @@ class touchosc_t : public TASCAR::module_base_t, TASCAR::service_t { private: uint32_t port; bool htmlcolors; + bool mutesounds = true; // std::vector obj; std::vector vmsg; std::vector vargv; @@ -598,7 +614,7 @@ int touchosc_t::osc_setfader(const char*, const char*, lo_arg** argv, int, } int touchosc_t::osc_setmute(const char*, const char*, lo_arg** argv, int, - lo_message msg, void* user_data) + lo_message msg, void* user_data) { lo_address src(lo_message_get_source(msg)); touchosc_t::chref_t* h((touchosc_t::chref_t*)user_data); @@ -683,7 +699,8 @@ void touchosc_t::connect(const std::string& host, uint32_t channels) delete it->second; it->second = NULL; } - connection_t* con(new connection_t(host, port, channels, htmlcolors)); + connection_t* con( + new connection_t(host, port, channels, htmlcolors, mutesounds)); routeports = session->find_route_ports({"/*"}); connections[host] = con; con->uploadsession(session, routeports); @@ -694,8 +711,11 @@ void touchosc_t::connect(const std::string& host, uint32_t channels) touchosc_t::touchosc_t(const TASCAR::module_cfg_t& cfg) : module_base_t(cfg), port(9000), htmlcolors(false) { - GET_ATTRIBUTE_(port); - GET_ATTRIBUTE_BOOL_(htmlcolors); + GET_ATTRIBUTE(port, "", "Port number of OSC device"); + GET_ATTRIBUTE_BOOL(htmlcolors, + "User HTML colors instead of touchosc default colors"); + GET_ATTRIBUTE_BOOL(mutesounds, + "Mute individual sounds instead of parent source"); pthread_mutex_init(&mtx, NULL); session->add_method("/touchosc/connect", "i", &touchosc_t::osc_connect, this); session->add_method("/touchosc/incscene", "f", &touchosc_t::osc_sceneinc,