WS: prepare for handling object disconnections

Use maps instead of vectors for holding strips and plugins
This allows to deal with "holes" after objects are removed

Also paves the way for a future improved way of identifying
individual strips and plugins
This commit is contained in:
Luciano Iam 2020-08-29 20:06:00 +02:00 committed by Robin Gareus
parent 7521d8ab6f
commit a8f917e7e2
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
5 changed files with 132 additions and 118 deletions

View file

@ -55,8 +55,9 @@ WebsocketsDispatcher::dispatch (Client client, const NodeStateMessage& msg)
void
WebsocketsDispatcher::update_all_nodes (Client client)
{
for (uint32_t strip_n = 0; strip_n < mixer ().strip_count (); ++strip_n) {
ArdourMixerStrip &strip = mixer ().nth_strip (strip_n);
for (ArdourMixer::StripMap::iterator it = mixer().strips().begin(); it != mixer().strips().end(); ++it) {
uint32_t strip_n = it->first;
ArdourMixerStrip& strip = it->second;
bool is_vca = strip.stripable ()->presentation_info ().flags () & ARDOUR::PresentationInfo::VCA;
@ -83,23 +84,23 @@ WebsocketsDispatcher::update_all_nodes (Client client)
update (client, Node::strip_pan, strip_n, strip.pan ());
for (uint32_t plugin_n = 0;; ++plugin_n) {
boost::shared_ptr<PluginInsert> insert = strip.nth_plugin (plugin_n).insert ();
if (!insert) {
break;
}
for (ArdourMixerStrip::PluginMap::iterator it = strip.plugins ().begin (); it != strip.plugins ().end (); ++it) {
uint32_t plugin_n = it->first;
boost::shared_ptr<PluginInsert> insert = it->second.insert ();
boost::shared_ptr<Plugin> plugin = insert->plugin ();
boost::shared_ptr<Plugin> plugin = insert->plugin ();
update (client, Node::strip_plugin_description, strip_n, plugin_n,
static_cast<std::string> (plugin->name ()));
update (client, Node::strip_plugin_enable, strip_n, plugin_n,
strip.nth_plugin (plugin_n).enabled ());
strip.plugin (plugin_n).enabled ());
for (uint32_t param_n = 0; param_n < plugin->parameter_count (); ++param_n) {
boost::shared_ptr<AutomationControl> a_ctrl =
strip.nth_plugin (plugin_n).param_control (param_n);
if (!a_ctrl) {
boost::shared_ptr<AutomationControl> a_ctrl;
try {
a_ctrl = strip.plugin (plugin_n).param_control (param_n);
} catch (ArdourMixerNotFoundException) {
continue;
}
@ -129,7 +130,7 @@ WebsocketsDispatcher::update_all_nodes (Client client)
update (client, Node::strip_plugin_param_description, addr, val);
TypedValue value = strip.nth_plugin (plugin_n).param_value (param_n);
TypedValue value = strip.plugin (plugin_n).param_value (param_n);
update (client, Node::strip_plugin_param_value, strip_n, plugin_n, param_n, value);
}
}
@ -189,9 +190,9 @@ WebsocketsDispatcher::strip_gain_handler (Client client, const NodeStateMessage&
uint32_t strip_id = state.nth_addr (0);
if (msg.is_write () && (state.n_val () > 0)) {
mixer ().nth_strip (strip_id).set_gain (state.nth_val (0));
mixer ().strip (strip_id).set_gain (state.nth_val (0));
} else {
update (client, Node::strip_gain, strip_id, mixer ().nth_strip (strip_id).gain ());
update (client, Node::strip_gain, strip_id, mixer ().strip (strip_id).gain ());
}
}
@ -207,9 +208,9 @@ WebsocketsDispatcher::strip_pan_handler (Client client, const NodeStateMessage&
uint32_t strip_id = state.nth_addr (0);
if (msg.is_write () && (state.n_val () > 0)) {
mixer ().nth_strip (strip_id).set_pan (state.nth_val (0));
mixer ().strip (strip_id).set_pan (state.nth_val (0));
} else {
update (client, Node::strip_pan, strip_id, mixer ().nth_strip (strip_id).pan ());
update (client, Node::strip_pan, strip_id, mixer ().strip (strip_id).pan ());
}
}
@ -225,9 +226,9 @@ WebsocketsDispatcher::strip_mute_handler (Client client, const NodeStateMessage&
uint32_t strip_id = state.nth_addr (0);
if (msg.is_write () && (state.n_val () > 0)) {
mixer ().nth_strip (strip_id).set_mute (state.nth_val (0));
mixer ().strip (strip_id).set_mute (state.nth_val (0));
} else {
update (client, Node::strip_mute, strip_id, mixer ().nth_strip (strip_id).mute ());
update (client, Node::strip_mute, strip_id, mixer ().strip (strip_id).mute ());
}
}
@ -244,10 +245,10 @@ WebsocketsDispatcher::strip_plugin_enable_handler (Client client, const NodeStat
uint32_t plugin_id = state.nth_addr (1);
if (msg.is_write () && (state.n_val () > 0)) {
mixer ().nth_strip (strip_id).nth_plugin (plugin_id).set_enabled (state.nth_val (0));
mixer ().strip (strip_id).plugin (plugin_id).set_enabled (state.nth_val (0));
} else {
update (client, Node::strip_plugin_enable, strip_id, plugin_id,
mixer ().nth_strip (strip_id).nth_plugin (plugin_id).enabled ());
mixer ().strip (strip_id).plugin (plugin_id).enabled ());
}
}
@ -265,10 +266,10 @@ WebsocketsDispatcher::strip_plugin_param_value_handler (Client client, const Nod
uint32_t param_id = state.nth_addr (2);
if (msg.is_write () && (state.n_val () > 0)) {
mixer ().nth_strip (strip_id).nth_plugin (plugin_id).set_param_value (param_id,
mixer ().strip (strip_id).plugin (plugin_id).set_param_value (param_id,
state.nth_val (0));
} else {
TypedValue value = mixer ().nth_strip (strip_id).nth_plugin (plugin_id).param_value (param_id);
TypedValue value = mixer ().strip (strip_id).plugin (plugin_id).param_value (param_id);
update (client, Node::strip_plugin_param_value, strip_id, plugin_id, param_id, value);
}
}

View file

@ -24,7 +24,6 @@
#include "transport.h"
#include "server.h"
#include "state.h"
#include "mixer.h"
// TO DO: make this configurable
#define POLL_INTERVAL_MS 100
@ -56,21 +55,21 @@ struct StripGainObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n)
{
// fires multiple times (4x as of ardour 6.0)
p->update_all (Node::strip_gain, strip_n, p->mixer ().nth_strip (strip_n).gain ());
p->update_all (Node::strip_gain, strip_n, p->mixer ().strip (strip_n).gain ());
}
};
struct StripPanObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n)
{
p->update_all (Node::strip_pan, strip_n, p->mixer ().nth_strip (strip_n).pan ());
p->update_all (Node::strip_pan, strip_n, p->mixer ().strip (strip_n).pan ());
}
};
struct StripMuteObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n)
{
p->update_all (Node::strip_mute, strip_n, p->mixer ().nth_strip (strip_n).mute ());
p->update_all (Node::strip_mute, strip_n, p->mixer ().strip (strip_n).mute ());
}
};
@ -78,7 +77,7 @@ struct PluginBypassObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n, uint32_t plugin_n)
{
p->update_all (Node::strip_plugin_enable, strip_n, plugin_n,
p->mixer ().nth_strip (strip_n).nth_plugin (plugin_n).enabled ());
p->mixer ().strip (strip_n).plugin (plugin_n).enabled ());
}
};
@ -87,9 +86,11 @@ struct PluginParamValueObserver {
uint32_t param_n, boost::weak_ptr<AutomationControl> ctrl)
{
boost::shared_ptr<AutomationControl> control = ctrl.lock ();
if (!control) {
return;
}
p->update_all (Node::strip_plugin_param_value, strip_n, plugin_n, param_n,
ArdourMixerPlugin::param_value (control));
}
@ -101,7 +102,7 @@ ArdourFeedback::start ()
observe_transport ();
observe_mixer ();
// some things need polling like the strip meters
// some values need polling like the strip meters
Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (POLL_INTERVAL_MS);
_periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this,
&ArdourFeedback::poll));
@ -179,9 +180,9 @@ ArdourFeedback::poll () const
{
update_all (Node::transport_time, transport ().time ());
for (uint32_t strip_n = 0; strip_n < mixer ().strip_count (); ++strip_n) {
float db = mixer ().nth_strip (strip_n).meter_level_db ();
update_all (Node::strip_meter, strip_n, static_cast<double> (db));
for (ArdourMixer::StripMap::iterator it = mixer().strips().begin(); it != mixer().strips().end(); ++it) {
float db = it->second.meter_level_db ();
update_all (Node::strip_meter, it->first, static_cast<double> (db));
}
return true;
@ -202,9 +203,12 @@ ArdourFeedback::observe_transport ()
void
ArdourFeedback::observe_mixer ()
{
for (uint32_t strip_n = 0; strip_n < mixer ().strip_count (); ++strip_n) {
boost::shared_ptr<Stripable> stripable = mixer ().nth_strip (strip_n).stripable ();
boost::shared_ptr<PBD::ScopedConnectionList> connections = mixer().nth_strip (strip_n).connections ();
for (ArdourMixer::StripMap::iterator it = mixer().strips().begin(); it != mixer().strips().end(); ++it) {
uint32_t strip_n = it->first;
ArdourMixerStrip& strip = it->second;
boost::shared_ptr<Stripable> stripable = strip.stripable ();
boost::shared_ptr<PBD::ScopedConnectionList> connections = it->second.connections ();
stripable->gain_control ()->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (StripGainObserver (), this, strip_n), event_loop ());
@ -217,23 +221,20 @@ ArdourFeedback::observe_mixer ()
stripable->mute_control ()->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (StripMuteObserver (), this, strip_n), event_loop ());
observe_strip_plugins (strip_n, stripable);
observe_strip_plugins (strip_n, strip.plugins ());
}
}
void
ArdourFeedback::observe_strip_plugins (uint32_t strip_n, boost::shared_ptr<ARDOUR::Stripable> strip)
ArdourFeedback::observe_strip_plugins (uint32_t strip_n, ArdourMixerStrip::PluginMap& plugins)
{
for (uint32_t plugin_n = 0;; ++plugin_n) {
boost::shared_ptr<PluginInsert> insert = mixer ().nth_strip (strip_n).nth_plugin (plugin_n).insert ();
if (!insert) {
break;
}
uint32_t bypass = insert->plugin ()->designated_bypass_port ();
Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass);
boost::shared_ptr<AutomationControl> control = insert->automation_control (param);
std::unique_ptr<PBD::ScopedConnectionList> connections (new PBD::ScopedConnectionList());
for (ArdourMixerStrip::PluginMap::iterator it = plugins.begin(); it != plugins.end(); ++it) {
uint32_t plugin_n = it->first;
boost::shared_ptr<PluginInsert> insert = it->second.insert ();
boost::shared_ptr<PBD::ScopedConnectionList> connections = it->second.connections ();
uint32_t bypass = insert->plugin ()->designated_bypass_port ();
Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass);
boost::shared_ptr<AutomationControl> control = insert->automation_control (param);
if (control) {
control->Changed.connect (*connections, MISSING_INVALIDATOR,
@ -257,17 +258,17 @@ ArdourFeedback::observe_strip_plugin_param_values (uint32_t strip_n,
boost::shared_ptr<Plugin> plugin = insert->plugin ();
for (uint32_t param_n = 0; param_n < plugin->parameter_count (); ++param_n) {
boost::shared_ptr<AutomationControl> control = mixer ().nth_strip (strip_n).nth_plugin (plugin_n).param_control (param_n);
try {
boost::shared_ptr<AutomationControl> control = mixer ().strip (strip_n).plugin (plugin_n).param_control (param_n);
if (!control) {
continue;
/*PBD::ScopedConnectionList *connections = _plugin_connections[(strip_n << 16) | plugin_n].get();
control->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (PluginParamValueObserver (), this, strip_n, plugin_n, param_n,
boost::weak_ptr<AutomationControl>(control)),
event_loop ());*/
} catch (ArdourMixerNotFoundException) {
/* ignore */
}
/*PBD::ScopedConnectionList *connections = _plugin_connections[(strip_n << 16) | plugin_n].get();
control->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (PluginParamValueObserver (), this, strip_n, plugin_n, param_n,
boost::weak_ptr<AutomationControl>(control)),
event_loop ());*/
}
}

View file

@ -25,6 +25,7 @@
#include "component.h"
#include "typed_value.h"
#include "mixer.h"
class ArdourFeedback : public SurfaceComponent
{
@ -50,9 +51,8 @@ private:
void observe_transport ();
void observe_mixer ();
void observe_strip_plugins (uint32_t, boost::shared_ptr<ARDOUR::Stripable>);
void observe_strip_plugin_param_values (uint32_t, uint32_t,
boost::shared_ptr<ARDOUR::PluginInsert>);
void observe_strip_plugins (uint32_t, ArdourMixerStrip::PluginMap&);
void observe_strip_plugin_param_values (uint32_t, uint32_t, boost::shared_ptr<ARDOUR::PluginInsert>);
};
#endif // _ardour_surface_websockets_feedback_h_

View file

@ -39,10 +39,16 @@ ArdourMixerPlugin::insert () const
return _insert;
}
boost::shared_ptr<PBD::ScopedConnectionList>
ArdourMixerPlugin::connections () const
{
return _connections;
}
bool
ArdourMixerPlugin::enabled () const
{
insert ()->enabled ();
return insert ()->enabled ();
}
void
@ -55,18 +61,15 @@ TypedValue
ArdourMixerPlugin::param_value (uint32_t param_n)
{
boost::shared_ptr<ARDOUR::AutomationControl> control = param_control (param_n);
TypedValue value = TypedValue ();
ParameterDescriptor pd = control->desc ();
TypedValue value = TypedValue ();
if (control) {
ParameterDescriptor pd = control->desc ();
if (pd.toggled) {
value = TypedValue (static_cast<bool> (control->get_value ()));
} else if (pd.enumeration || pd.integer_step) {
value = TypedValue (static_cast<int> (control->get_value ()));
} else {
value = TypedValue (control->get_value ());
}
if (pd.toggled) {
value = TypedValue (static_cast<bool> (control->get_value ()));
} else if (pd.enumeration || pd.integer_step) {
value = TypedValue (static_cast<int> (control->get_value ()));
} else {
value = TypedValue (control->get_value ());
}
return value;
@ -76,21 +79,18 @@ void
ArdourMixerPlugin::set_param_value (uint32_t param_n, TypedValue value)
{
boost::shared_ptr<AutomationControl> control = param_control (param_n);
ParameterDescriptor pd = control->desc ();
double dbl_val;
if (control) {
ParameterDescriptor pd = control->desc ();
double dbl_val;
if (pd.toggled) {
dbl_val = static_cast<double> (static_cast<bool> (value));
} else if (pd.enumeration || pd.integer_step) {
dbl_val = static_cast<double> (static_cast<int> (value));
} else {
dbl_val = static_cast<double> (value);
}
control->set_value (dbl_val, PBD::Controllable::NoGroup);
if (pd.toggled) {
dbl_val = static_cast<double> (static_cast<bool> (value));
} else if (pd.enumeration || pd.integer_step) {
dbl_val = static_cast<double> (static_cast<int> (value));
} else {
dbl_val = static_cast<double> (value);
}
control->set_value (dbl_val, PBD::Controllable::NoGroup);
}
boost::shared_ptr<ARDOUR::AutomationControl>
@ -113,6 +113,7 @@ ArdourMixerStrip::ArdourMixerStrip (boost::shared_ptr<ARDOUR::Stripable> stripab
, _connections (boost::shared_ptr<PBD::ScopedConnectionList> (new PBD::ScopedConnectionList()))
{
if (_stripable->presentation_info ().flags () & ARDOUR::PresentationInfo::VCA) {
/* no plugins to handle */
return;
}
@ -125,13 +126,15 @@ ArdourMixerStrip::ArdourMixerStrip (boost::shared_ptr<ARDOUR::Stripable> stripab
for (uint32_t plugin_n = 0;; ++plugin_n) {
boost::shared_ptr<Processor> processor = route->nth_plugin (plugin_n);
if (processor) {
boost::shared_ptr<PluginInsert> insert = boost::static_pointer_cast<PluginInsert> (processor);
if (!processor) {
break;
}
if (insert) {
ArdourMixerPlugin plugin (insert);
_plugins.push_back (plugin);
}
boost::shared_ptr<PluginInsert> insert = boost::static_pointer_cast<PluginInsert> (processor);
if (insert) {
ArdourMixerPlugin plugin (insert);
_plugins.emplace (plugin_n, plugin);
}
}
}
@ -148,20 +151,20 @@ ArdourMixerStrip::connections () const
return _connections;
}
int
ArdourMixerStrip::plugin_count () const
{
return _plugins.size ();
}
ArdourMixerPlugin&
ArdourMixerStrip::nth_plugin (uint32_t plugin_n)
ArdourMixerStrip::plugin (uint32_t plugin_n)
{
if (plugin_n < _plugins.size ()) {
return _plugins[plugin_n];
if (_plugins.find (plugin_n) == _plugins.end ()) {
throw ArdourMixerNotFoundException ("plugin id = " + boost::lexical_cast<std::string>(plugin_n) + " not found");
}
throw ArdourMixerNotFoundException ("plugin id = " + boost::lexical_cast<std::string>(plugin_n) + " not found");
return _plugins.at (plugin_n);
}
ArdourMixerStrip::PluginMap&
ArdourMixerStrip::plugins ()
{
return _plugins;
}
double
@ -180,9 +183,11 @@ double
ArdourMixerStrip::pan () const
{
boost::shared_ptr<AutomationControl> ac = _stripable->pan_azimuth_control ();
if (!ac) {
throw ArdourMixerNotFoundException ("strip has no panner");
}
return ac->internal_to_interface (ac->get_value ());
}
@ -190,9 +195,11 @@ void
ArdourMixerStrip::set_pan (double value)
{
boost::shared_ptr<AutomationControl> ac = _stripable->pan_azimuth_control ();
if (!ac) {
return;
}
ac->set_value (ac->interface_to_internal (value), PBD::Controllable::NoGroup);
}
@ -265,8 +272,7 @@ ArdourMixer::start ()
ArdourMixerStrip strip (*it);
//(*it)->DropReferences.connect (_connections, MISSING_INVALIDATOR,
// boost::bind (&ArdourMixer::on_drop_strip, this, strip_n), event_loop ());
_strips.push_back (strip);
strip_n++;
_strips.emplace (strip_n++, strip);
}
return 0;
@ -279,20 +285,21 @@ ArdourMixer::stop ()
return 0;
}
uint32_t
ArdourMixer::strip_count () const
ArdourMixer::StripMap&
ArdourMixer::strips ()
{
return _strips.size ();
return _strips;
}
ArdourMixerStrip&
ArdourMixer::nth_strip (uint32_t strip_n)
ArdourMixer::strip (uint32_t strip_n)
{
if (strip_n < _strips.size ()) {
return _strips[strip_n];
if (_strips.find (strip_n) == _strips.end ()) {
throw ArdourMixerNotFoundException ("strip id = " + boost::lexical_cast<std::string>(strip_n) + " not found");
}
throw ArdourMixerNotFoundException ("strip id = " + boost::lexical_cast<std::string>(strip_id) + " not found");
return _strips.at (strip_n);
}
void

View file

@ -33,7 +33,8 @@ public:
ArdourMixerPlugin (boost::shared_ptr<ARDOUR::PluginInsert>);
boost::shared_ptr<ARDOUR::PluginInsert> insert () const;
boost::shared_ptr<PBD::ScopedConnectionList> connections () const;
bool enabled () const;
void set_enabled (bool);
@ -58,8 +59,10 @@ public:
boost::shared_ptr<ARDOUR::Stripable> stripable () const;
boost::shared_ptr<PBD::ScopedConnectionList> connections () const;
int plugin_count () const;
ArdourMixerPlugin& nth_plugin (uint32_t);
typedef std::map<uint32_t, ArdourMixerPlugin> PluginMap;
PluginMap& plugins ();
ArdourMixerPlugin& plugin (uint32_t);
double gain () const;
void set_gain (double);
@ -80,7 +83,8 @@ public:
private:
boost::shared_ptr<ARDOUR::Stripable> _stripable;
boost::shared_ptr<PBD::ScopedConnectionList> _connections;
std::vector<ArdourMixerPlugin> _plugins;
PluginMap _plugins;
void on_drop_plugin (uint32_t);
@ -96,13 +100,14 @@ public:
int start ();
int stop ();
uint32_t strip_count () const;
ArdourMixerStrip& nth_strip (uint32_t);
typedef std::map<uint32_t, ArdourMixerStrip> StripMap;
StripMap& strips ();
ArdourMixerStrip& strip (uint32_t);
void on_drop_strip (uint32_t);
private:
typedef std::vector<ArdourMixerStrip> StripsVector;
StripsVector _strips;
StripMap _strips;
};
#endif // _ardour_surface_websockets_mixer_h_