NO-OP: Re-indent websockets code

"Always use Tabstops for block-indent (the code must be
formatted correctly with "[TAB] = N spaces" for any value of N).
Use space only for alignment." - https://ardour.org/styleguide.html
This commit is contained in:
Robin Gareus 2020-02-23 16:03:59 +01:00
parent 224be91211
commit 5e3480ba8f
No known key found for this signature in database
GPG key ID: A090BCE02CF57F04
23 changed files with 1260 additions and 1217 deletions

View file

@ -35,7 +35,7 @@ using namespace ArdourSurface;
#include "pbd/abstract_ui.cc" // instantiate template #include "pbd/abstract_ui.cc" // instantiate template
ArdourWebsockets::ArdourWebsockets (Session& s) ArdourWebsockets::ArdourWebsockets (Session& s)
: ControlProtocol (s, X_(SURFACE_NAME)) : ControlProtocol (s, X_ (SURFACE_NAME))
, AbstractUI<ArdourWebsocketsUIRequest> (name ()) , AbstractUI<ArdourWebsocketsUIRequest> (name ())
, _strips (*this) , _strips (*this)
, _globals (*this) , _globals (*this)
@ -43,94 +43,95 @@ ArdourWebsockets::ArdourWebsockets (Session& s)
, _server (*this) , _server (*this)
, _dispatcher (*this) , _dispatcher (*this)
{ {
_components.push_back (&_strips); _components.push_back (&_strips);
_components.push_back (&_globals); _components.push_back (&_globals);
_components.push_back (&_server); _components.push_back (&_server);
_components.push_back (&_feedback); _components.push_back (&_feedback);
_components.push_back (&_dispatcher); _components.push_back (&_dispatcher);
} }
ArdourWebsockets::~ArdourWebsockets () ArdourWebsockets::~ArdourWebsockets ()
{ {
stop(); stop ();
} }
void* void*
ArdourWebsockets::request_factory (uint32_t num_requests) ArdourWebsockets::request_factory (uint32_t num_requests)
{ {
/* AbstractUI<T>::request_buffer_factory() is a template method only /* AbstractUI<T>::request_buffer_factory() is a template method only
instantiated in this source module. To provide something visible for instantiated in this source module. To provide something visible for
use in the interface/descriptor, we have this static method that is use in the interface/descriptor, we have this static method that is
template-free. template-free.
*/ */
return request_buffer_factory (num_requests); return request_buffer_factory (num_requests);
} }
int int
ArdourWebsockets::set_active (bool yn) ArdourWebsockets::set_active (bool yn)
{ {
if (yn != active ()) { if (yn != active ()) {
if (yn) { if (yn) {
if (start ()) { if (start ()) {
return -1; return -1;
} }
} else { } else {
if (stop ()) { if (stop ()) {
return -1; return -1;
} }
} }
} }
return ControlProtocol::set_active (yn); return ControlProtocol::set_active (yn);
} }
void void
ArdourWebsockets::thread_init () ArdourWebsockets::thread_init ()
{ {
pthread_set_name (event_loop_name ().c_str ()); pthread_set_name (event_loop_name ().c_str ());
PBD::notify_event_loops_about_thread_creation (pthread_self (), event_loop_name (), 2048); PBD::notify_event_loops_about_thread_creation (pthread_self (), event_loop_name (), 2048);
SessionEvent::create_per_thread_pool (event_loop_name (), 128); SessionEvent::create_per_thread_pool (event_loop_name (), 128);
} }
void void
ArdourWebsockets::do_request (ArdourWebsocketsUIRequest* req) ArdourWebsockets::do_request (ArdourWebsocketsUIRequest* req)
{ {
if (req->type == CallSlot) { if (req->type == CallSlot) {
call_slot (MISSING_INVALIDATOR, req->the_slot); call_slot (MISSING_INVALIDATOR, req->the_slot);
} else if (req->type == Quit) { } else if (req->type == Quit) {
stop (); stop ();
} }
} }
int int
ArdourWebsockets::start () ArdourWebsockets::start ()
{ {
// startup the event loop thread /* startup the event loop thread */
BaseUI::run (); BaseUI::run ();
for (std::vector<SurfaceComponent *>::iterator it = _components.begin (); for (std::vector<SurfaceComponent*>::iterator it = _components.begin ();
it != _components.end (); ++it) { it != _components.end (); ++it) {
int rc = (*it)->start (); int rc = (*it)->start ();
if (rc != 0) { if (rc != 0) {
return -1; return -1;
} }
} }
PBD::info << "ArdourWebsockets: started" << endmsg; PBD::info << "ArdourWebsockets: started" << endmsg;
return 0; return 0;
} }
int int
ArdourWebsockets::stop () { ArdourWebsockets::stop ()
for (std::vector<SurfaceComponent *>::iterator it = _components.begin (); {
it != _components.end (); ++it) { for (std::vector<SurfaceComponent*>::iterator it = _components.begin ();
(*it)->stop (); it != _components.end (); ++it) {
} (*it)->stop ();
}
BaseUI::quit (); BaseUI::quit ();
PBD::info << "ArdourWebsockets: stopped" << endmsg;
return 0; PBD::info << "ArdourWebsockets: stopped" << endmsg;
return 0;
} }

View file

@ -33,66 +33,77 @@
#include "control_protocol/control_protocol.h" #include "control_protocol/control_protocol.h"
#include "component.h" #include "component.h"
#include "strips.h" #include "dispatcher.h"
#include "feedback.h"
#include "globals.h" #include "globals.h"
#include "server.h" #include "server.h"
#include "feedback.h" #include "strips.h"
#include "dispatcher.h"
#define SURFACE_NAME "WebSockets Server (Experimental)" #define SURFACE_NAME "WebSockets Server (Experimental)"
#define SURFACE_ID "uri://ardour.org/surfaces/ardour_websockets:0" #define SURFACE_ID "uri://ardour.org/surfaces/ardour_websockets:0"
namespace ArdourSurface {
namespace ArdourSurface
{
struct ArdourWebsocketsUIRequest : public BaseUI::BaseRequestObject { struct ArdourWebsocketsUIRequest : public BaseUI::BaseRequestObject {
public: public:
ArdourWebsocketsUIRequest () {} ArdourWebsocketsUIRequest () {}
~ArdourWebsocketsUIRequest () {} ~ArdourWebsocketsUIRequest () {}
}; };
class ArdourWebsockets : public ARDOUR::ControlProtocol, class ArdourWebsockets : public ARDOUR::ControlProtocol,
public AbstractUI<ArdourWebsocketsUIRequest> public AbstractUI<ArdourWebsocketsUIRequest>
{ {
public: public:
ArdourWebsockets (ARDOUR::Session&);
ArdourWebsockets (ARDOUR::Session&); virtual ~ArdourWebsockets ();
virtual ~ArdourWebsockets ();
static void* request_factory (uint32_t); static void* request_factory (uint32_t);
int set_active (bool); int set_active (bool);
ARDOUR::Session& ardour_session () { return *session; } ARDOUR::Session& ardour_session ()
ArdourStrips& strips_component () { return _strips; } {
ArdourGlobals& globals_component () { return _globals; } return *session;
WebsocketsServer& server_component () { return _server; } }
WebsocketsDispatcher& dispatcher_component () { return _dispatcher; } ArdourStrips& strips_component ()
{
return _strips;
}
ArdourGlobals& globals_component ()
{
return _globals;
}
WebsocketsServer& server_component ()
{
return _server;
}
WebsocketsDispatcher& dispatcher_component ()
{
return _dispatcher;
}
// ControlProtocol /* ControlProtocol */
void stripable_selection_changed () {} void stripable_selection_changed () {}
protected: protected:
/* BaseUI */
void thread_init ();
// BaseUI /* AbstractUI */
void thread_init (); void do_request (ArdourWebsocketsUIRequest*);
// AbstractUI
void do_request (ArdourWebsocketsUIRequest*);
private: private:
ArdourStrips _strips;
ArdourStrips _strips; ArdourGlobals _globals;
ArdourGlobals _globals; ArdourFeedback _feedback;
ArdourFeedback _feedback; WebsocketsServer _server;
WebsocketsServer _server; WebsocketsDispatcher _dispatcher;
WebsocketsDispatcher _dispatcher; std::vector<SurfaceComponent*> _components;
std::vector<SurfaceComponent *> _components;
int start ();
int stop ();
int start ();
int stop ();
}; };
} // namespace } // namespace ArdourSurface
#endif // ardour_websockets_h #endif // ardour_websockets_h

View file

@ -23,49 +23,49 @@
bool bool
ClientContext::has_state (const NodeState& node_state) ClientContext::has_state (const NodeState& node_state)
{ {
ClientState::iterator it = _state.find (node_state); ClientState::iterator it = _state.find (node_state);
if (it == _state.end ()) { if (it == _state.end ()) {
return false; return false;
} }
int n_val = node_state.n_val (); int n_val = node_state.n_val ();
if (it->n_val () != n_val) { if (it->n_val () != n_val) {
return false; return false;
} }
for (int i = 0; i < n_val; i++) { for (int i = 0; i < n_val; i++) {
if (it->nth_val (i) != node_state.nth_val (i)) { if (it->nth_val (i) != node_state.nth_val (i)) {
return false; return false;
} }
} }
return true; return true;
} }
void void
ClientContext::update_state (const NodeState& node_state) ClientContext::update_state (const NodeState& node_state)
{ {
ClientState::iterator it = _state.find (node_state); ClientState::iterator it = _state.find (node_state);
if (it != _state.end ()) { if (it != _state.end ()) {
_state.erase (it); _state.erase (it);
} }
_state.insert (node_state); _state.insert (node_state);
} }
std::string std::string
ClientContext::debug_str () ClientContext::debug_str ()
{ {
std::stringstream ss; std::stringstream ss;
ss << "client = " << std::hex << _wsi << std::endl; ss << "client = " << std::hex << _wsi << std::endl;
for (ClientState::iterator it = _state.begin (); it != _state.end (); ++it) {
ss << " - " << it->debug_str () << std::endl;
}
return ss.str (); for (ClientState::iterator it = _state.begin (); it != _state.end (); ++it) {
ss << " - " << it->debug_str () << std::endl;
}
return ss.str ();
} }

View file

@ -22,37 +22,41 @@
#include <boost/unordered_set.hpp> #include <boost/unordered_set.hpp>
#include <list> #include <list>
#include "state.h"
#include "message.h" #include "message.h"
#include "state.h"
typedef struct lws* Client; typedef struct lws* Client;
typedef std::list<NodeStateMessage> ClientOutputBuffer; typedef std::list<NodeStateMessage> ClientOutputBuffer;
class ClientContext class ClientContext
{ {
public: public:
ClientContext (Client wsi)
: _wsi (wsi){};
virtual ~ClientContext (){};
ClientContext (Client wsi) : _wsi(wsi) {}; Client wsi () const
virtual ~ClientContext () {}; {
return _wsi;
}
Client wsi () const { return _wsi; } bool has_state (const NodeState&);
void update_state (const NodeState&);
bool has_state (const NodeState&); ClientOutputBuffer& output_buf ()
void update_state (const NodeState&); {
return _output_buf;
}
ClientOutputBuffer& output_buf () { return _output_buf; } std::string debug_str ();
std::string debug_str ();
private: private:
Client _wsi;
Client _wsi; typedef boost::unordered_set<NodeState> ClientState;
ClientState _state;
typedef boost::unordered_set<NodeState> ClientState;
ClientState _state;
ClientOutputBuffer _output_buf;
ClientOutputBuffer _output_buf;
}; };
#endif // client_context_h #endif // client_context_h

View file

@ -22,41 +22,41 @@
PBD::EventLoop* PBD::EventLoop*
SurfaceComponent::event_loop () const SurfaceComponent::event_loop () const
{ {
return static_cast<PBD::EventLoop*>(&_surface); return static_cast<PBD::EventLoop*> (&_surface);
} }
Glib::RefPtr<Glib::MainLoop> Glib::RefPtr<Glib::MainLoop>
SurfaceComponent::main_loop () const SurfaceComponent::main_loop () const
{ {
return _surface.main_loop (); return _surface.main_loop ();
} }
ARDOUR::Session& ARDOUR::Session&
SurfaceComponent::session () const SurfaceComponent::session () const
{ {
return _surface.ardour_session (); return _surface.ardour_session ();
} }
ArdourStrips& ArdourStrips&
SurfaceComponent::strips () const SurfaceComponent::strips () const
{ {
return _surface.strips_component (); return _surface.strips_component ();
} }
ArdourGlobals& ArdourGlobals&
SurfaceComponent::globals () const SurfaceComponent::globals () const
{ {
return _surface.globals_component (); return _surface.globals_component ();
} }
WebsocketsServer& WebsocketsServer&
SurfaceComponent::server () const SurfaceComponent::server () const
{ {
return _surface.server_component (); return _surface.server_component ();
} }
WebsocketsDispatcher& WebsocketsDispatcher&
SurfaceComponent::dispatcher () const SurfaceComponent::dispatcher () const
{ {
return _surface.dispatcher_component (); return _surface.dispatcher_component ();
} }

View file

@ -24,8 +24,9 @@
#include "ardour/session.h" #include "ardour/session.h"
#include "pbd/event_loop.h" #include "pbd/event_loop.h"
namespace ArdourSurface { namespace ArdourSurface
class ArdourWebsockets; {
class ArdourWebsockets;
} }
class ArdourStrips; class ArdourStrips;
@ -35,27 +36,31 @@ class WebsocketsDispatcher;
class SurfaceComponent class SurfaceComponent
{ {
public: public:
SurfaceComponent (ArdourSurface::ArdourWebsockets& surface)
: _surface (surface){};
SurfaceComponent (ArdourSurface::ArdourWebsockets& surface) : _surface (surface) {}; virtual ~SurfaceComponent (){};
virtual ~SurfaceComponent () {}; virtual int start ()
{
return 0;
}
virtual int stop ()
{
return 0;
}
virtual int start () { return 0; } PBD::EventLoop* event_loop () const;
virtual int stop () { return 0; } Glib::RefPtr<Glib::MainLoop> main_loop () const;
ARDOUR::Session& session () const;
PBD::EventLoop* event_loop () const; ArdourStrips& strips () const;
Glib::RefPtr<Glib::MainLoop> main_loop() const; ArdourGlobals& globals () const;
ARDOUR::Session& session () const; WebsocketsServer& server () const;
ArdourStrips& strips () const; WebsocketsDispatcher& dispatcher () const;
ArdourGlobals& globals () const;
WebsocketsServer& server () const;
WebsocketsDispatcher& dispatcher () const;
protected:
ArdourSurface::ArdourWebsockets& _surface;
protected:
ArdourSurface::ArdourWebsockets& _surface;
}; };
#endif // surface_component_h #endif // surface_component_h

View file

@ -20,234 +20,233 @@
#include "ardour/plugin_insert.h" #include "ardour/plugin_insert.h"
#include "dispatcher.h"
#include "ardour_websockets.h" #include "ardour_websockets.h"
#include "dispatcher.h"
#include "state.h" #include "state.h"
using namespace ARDOUR; using namespace ARDOUR;
#define NODE_METHOD_PAIR(x) (Node::x, &WebsocketsDispatcher::x ## _handler) #define NODE_METHOD_PAIR(x) (Node::x, &WebsocketsDispatcher::x##_handler)
WebsocketsDispatcher::NodeMethodMap WebsocketsDispatcher::NodeMethodMap
WebsocketsDispatcher::_node_to_method = boost::assign::map_list_of WebsocketsDispatcher::_node_to_method = boost::assign::map_list_of
NODE_METHOD_PAIR(tempo) NODE_METHOD_PAIR (tempo)
NODE_METHOD_PAIR(strip_gain) NODE_METHOD_PAIR (strip_gain)
NODE_METHOD_PAIR(strip_pan) NODE_METHOD_PAIR (strip_pan)
NODE_METHOD_PAIR(strip_mute) NODE_METHOD_PAIR (strip_mute)
NODE_METHOD_PAIR(strip_plugin_enable) NODE_METHOD_PAIR (strip_plugin_enable)
NODE_METHOD_PAIR(strip_plugin_param_value) NODE_METHOD_PAIR (strip_plugin_param_value);
;
void void
WebsocketsDispatcher::dispatch (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::dispatch (Client client, const NodeStateMessage& msg)
{ {
NodeMethodMap::iterator it = _node_to_method.find (msg.state ().node ()); NodeMethodMap::iterator it = _node_to_method.find (msg.state ().node ());
if (it != _node_to_method.end ()) { if (it != _node_to_method.end ()) {
try { try {
(this->*it->second) (client, msg); (this->*it->second) (client, msg);
} catch (const std::exception& e) { } catch (const std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what () << std::endl;
} }
} }
} }
void void
WebsocketsDispatcher::update_all_nodes (Client client) WebsocketsDispatcher::update_all_nodes (Client client)
{ {
update (client, Node::tempo, globals ().tempo ()); update (client, Node::tempo, globals ().tempo ());
for (uint32_t strip_n = 0; strip_n < strips ().strip_count (); ++strip_n) { for (uint32_t strip_n = 0; strip_n < strips ().strip_count (); ++strip_n) {
boost::shared_ptr<Stripable> strip = strips ().nth_strip (strip_n); boost::shared_ptr<Stripable> strip = strips ().nth_strip (strip_n);
boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (strip); boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (strip);
if (!route) { if (!route) {
continue; continue;
} }
update (client, Node::strip_desc, strip_n, strip->name ()); update (client, Node::strip_desc, strip_n, strip->name ());
update (client, Node::strip_gain, strip_n, strips ().strip_gain (strip_n)); update (client, Node::strip_gain, strip_n, strips ().strip_gain (strip_n));
update (client, Node::strip_pan, strip_n, strips ().strip_pan (strip_n)); update (client, Node::strip_pan, strip_n, strips ().strip_pan (strip_n));
update (client, Node::strip_mute, strip_n, strips ().strip_mute (strip_n)); update (client, Node::strip_mute, strip_n, strips ().strip_mute (strip_n));
for (uint32_t plugin_n = 0 ; ; ++plugin_n) { for (uint32_t plugin_n = 0;; ++plugin_n) {
boost::shared_ptr<PluginInsert> insert = strips () boost::shared_ptr<PluginInsert> insert = strips ()
.strip_plugin_insert (strip_n, plugin_n); .strip_plugin_insert (strip_n, plugin_n);
if (!insert) { if (!insert) {
break; break;
} }
boost::shared_ptr<Plugin> plugin = insert->plugin (); boost::shared_ptr<Plugin> plugin = insert->plugin ();
update (client, Node::strip_plugin_desc, strip_n, plugin_n, update (client, Node::strip_plugin_desc, strip_n, plugin_n,
static_cast<std::string>(plugin->name ())); static_cast<std::string> (plugin->name ()));
update (client, Node::strip_plugin_enable, strip_n, plugin_n, update (client, Node::strip_plugin_enable, strip_n, plugin_n,
strips ().strip_plugin_enabled (strip_n, plugin_n)); strips ().strip_plugin_enabled (strip_n, plugin_n));
for (uint32_t param_n = 0; param_n < plugin->parameter_count (); ++param_n) { for (uint32_t param_n = 0; param_n < plugin->parameter_count (); ++param_n) {
boost::shared_ptr<AutomationControl> a_ctrl = boost::shared_ptr<AutomationControl> a_ctrl =
strips ().strip_plugin_param_control (strip_n, plugin_n, param_n); strips ().strip_plugin_param_control (strip_n, plugin_n, param_n);
if (!a_ctrl) { if (!a_ctrl) {
continue; continue;
} }
AddressVector addr = AddressVector (); AddressVector addr = AddressVector ();
addr.push_back (strip_n); addr.push_back (strip_n);
addr.push_back (plugin_n); addr.push_back (plugin_n);
addr.push_back (param_n); addr.push_back (param_n);
ValueVector val = ValueVector (); ValueVector val = ValueVector ();
val.push_back (a_ctrl->name ()); val.push_back (a_ctrl->name ());
// possible flags: enumeration, integer_step, logarithmic, sr_dependent, toggled // possible flags: enumeration, integer_step, logarithmic, sr_dependent, toggled
ParameterDescriptor pd = a_ctrl->desc (); ParameterDescriptor pd = a_ctrl->desc ();
if (pd.toggled) { if (pd.toggled) {
val.push_back (std::string("b")); val.push_back (std::string ("b"));
} else if (pd.enumeration || pd.integer_step) { } else if (pd.enumeration || pd.integer_step) {
val.push_back (std::string("i")); val.push_back (std::string ("i"));
val.push_back (pd.lower); val.push_back (pd.lower);
val.push_back (pd.upper); val.push_back (pd.upper);
val.push_back (pd.integer_step); val.push_back (pd.integer_step);
} else { } else {
val.push_back (std::string("d")); val.push_back (std::string ("d"));
val.push_back (pd.lower); val.push_back (pd.lower);
val.push_back (pd.upper); val.push_back (pd.upper);
val.push_back (pd.logarithmic); val.push_back (pd.logarithmic);
} }
update (client, Node::strip_plugin_param_desc, addr, val); update (client, Node::strip_plugin_param_desc, addr, val);
TypedValue value = strips ().strip_plugin_param_value (strip_n, plugin_n, param_n); TypedValue value = strips ().strip_plugin_param_value (strip_n, plugin_n, param_n);
update (client, Node::strip_plugin_param_value, strip_n, plugin_n, param_n, value); update (client, Node::strip_plugin_param_value, strip_n, plugin_n, param_n, value);
} }
} }
} }
} }
void void
WebsocketsDispatcher::tempo_handler (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::tempo_handler (Client client, const NodeStateMessage& msg)
{ {
if (msg.is_write ()) { if (msg.is_write ()) {
globals ().set_tempo (msg.state ().nth_val (0)); globals ().set_tempo (msg.state ().nth_val (0));
} else { } else {
update (client, Node::tempo, globals ().tempo ()); update (client, Node::tempo, globals ().tempo ());
} }
} }
void void
WebsocketsDispatcher::strip_gain_handler (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::strip_gain_handler (Client client, const NodeStateMessage& msg)
{ {
uint32_t strip_id = msg.state ().nth_addr (0); uint32_t strip_id = msg.state ().nth_addr (0);
if (msg.is_write ()) { if (msg.is_write ()) {
strips ().set_strip_gain (strip_id, msg.state ().nth_val (0)); strips ().set_strip_gain (strip_id, msg.state ().nth_val (0));
} else { } else {
update (client, Node::strip_gain, strip_id, strips ().strip_gain (strip_id)); update (client, Node::strip_gain, strip_id, strips ().strip_gain (strip_id));
} }
} }
void void
WebsocketsDispatcher::strip_pan_handler (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::strip_pan_handler (Client client, const NodeStateMessage& msg)
{ {
uint32_t strip_id = msg.state ().nth_addr (0); uint32_t strip_id = msg.state ().nth_addr (0);
if (msg.is_write ()) { if (msg.is_write ()) {
strips ().set_strip_pan (strip_id, msg.state ().nth_val (0)); strips ().set_strip_pan (strip_id, msg.state ().nth_val (0));
} else { } else {
update (client, Node::strip_pan, strip_id, strips ().strip_pan(strip_id)); update (client, Node::strip_pan, strip_id, strips ().strip_pan (strip_id));
} }
} }
void void
WebsocketsDispatcher::strip_mute_handler (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::strip_mute_handler (Client client, const NodeStateMessage& msg)
{ {
uint32_t strip_id = msg.state ().nth_addr (0); uint32_t strip_id = msg.state ().nth_addr (0);
if (msg.is_write ()) { if (msg.is_write ()) {
strips ().set_strip_mute (strip_id, msg.state ().nth_val (0)); strips ().set_strip_mute (strip_id, msg.state ().nth_val (0));
} else { } else {
update (client, Node::strip_mute, strip_id, strips ().strip_mute (strip_id)); update (client, Node::strip_mute, strip_id, strips ().strip_mute (strip_id));
} }
} }
void void
WebsocketsDispatcher::strip_plugin_enable_handler (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::strip_plugin_enable_handler (Client client, const NodeStateMessage& msg)
{ {
uint32_t strip_id = msg.state ().nth_addr (0); uint32_t strip_id = msg.state ().nth_addr (0);
uint32_t plugin_id = msg.state ().nth_addr (1); uint32_t plugin_id = msg.state ().nth_addr (1);
if (msg.is_write ()) { if (msg.is_write ()) {
strips ().set_strip_plugin_enabled (strip_id, plugin_id, msg.state ().nth_val (0)); strips ().set_strip_plugin_enabled (strip_id, plugin_id, msg.state ().nth_val (0));
} else { } else {
update (client, Node::strip_plugin_enable, strip_id, plugin_id, update (client, Node::strip_plugin_enable, strip_id, plugin_id,
strips ().strip_plugin_enabled (strip_id, plugin_id)); strips ().strip_plugin_enabled (strip_id, plugin_id));
} }
} }
void void
WebsocketsDispatcher::strip_plugin_param_value_handler (Client client, const NodeStateMessage& msg) WebsocketsDispatcher::strip_plugin_param_value_handler (Client client, const NodeStateMessage& msg)
{ {
uint32_t strip_id = msg.state ().nth_addr (0); uint32_t strip_id = msg.state ().nth_addr (0);
uint32_t plugin_id = msg.state ().nth_addr (1); uint32_t plugin_id = msg.state ().nth_addr (1);
uint32_t param_id = msg.state ().nth_addr (2); uint32_t param_id = msg.state ().nth_addr (2);
if (msg.is_write ()) { if (msg.is_write ()) {
strips ().set_strip_plugin_param_value (strip_id, plugin_id, param_id, strips ().set_strip_plugin_param_value (strip_id, plugin_id, param_id,
msg.state ().nth_val (0)); msg.state ().nth_val (0));
} else { } else {
TypedValue value = strips ().strip_plugin_param_value (strip_id, plugin_id, param_id); TypedValue value = strips ().strip_plugin_param_value (strip_id, plugin_id, param_id);
update (client, Node::strip_plugin_param_value, strip_id, plugin_id, param_id, value); update (client, Node::strip_plugin_param_value, strip_id, plugin_id, param_id, value);
} }
} }
void void
WebsocketsDispatcher::update (Client client, std::string node, TypedValue val1) WebsocketsDispatcher::update (Client client, std::string node, TypedValue val1)
{ {
update (client, node, ADDR_NONE, ADDR_NONE, ADDR_NONE, val1); update (client, node, ADDR_NONE, ADDR_NONE, ADDR_NONE, val1);
} }
void void
WebsocketsDispatcher::update (Client client, std::string node, uint32_t strip_n, TypedValue val1) WebsocketsDispatcher::update (Client client, std::string node, uint32_t strip_n, TypedValue val1)
{ {
update (client, node, strip_n, ADDR_NONE, ADDR_NONE, val1); update (client, node, strip_n, ADDR_NONE, ADDR_NONE, val1);
} }
void void
WebsocketsDispatcher::update (Client client, std::string node, uint32_t strip_n, uint32_t plugin_n, WebsocketsDispatcher::update (Client client, std::string node, uint32_t strip_n, uint32_t plugin_n,
TypedValue val1) TypedValue val1)
{ {
update (client, node, strip_n, plugin_n, ADDR_NONE, val1); update (client, node, strip_n, plugin_n, ADDR_NONE, val1);
} }
void void
WebsocketsDispatcher::update (Client client, std::string node, uint32_t strip_n, uint32_t plugin_n, WebsocketsDispatcher::update (Client client, std::string node, uint32_t strip_n, uint32_t plugin_n,
uint32_t param_n, TypedValue val1) uint32_t param_n, TypedValue val1)
{ {
AddressVector addr = AddressVector (); AddressVector addr = AddressVector ();
if (strip_n != ADDR_NONE) { if (strip_n != ADDR_NONE) {
addr.push_back (strip_n); addr.push_back (strip_n);
} }
if (plugin_n != ADDR_NONE) { if (plugin_n != ADDR_NONE) {
addr.push_back (plugin_n); addr.push_back (plugin_n);
} }
if (param_n != ADDR_NONE) { if (param_n != ADDR_NONE) {
addr.push_back (param_n); addr.push_back (param_n);
} }
ValueVector val = ValueVector (); ValueVector val = ValueVector ();
if (!val1.empty ()) { if (!val1.empty ()) {
val.push_back (val1); val.push_back (val1);
} }
update (client, node, addr, val); update (client, node, addr, val);
} }
void void
WebsocketsDispatcher::update (Client client, std::string node, const AddressVector& addr, WebsocketsDispatcher::update (Client client, std::string node, const AddressVector& addr,
const ValueVector& val) const ValueVector& val)
{ {
server ().update_client (client, NodeState (node, addr, val), true); server ().update_client (client, NodeState (node, addr, val), true);
} }

View file

@ -21,41 +21,38 @@
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "component.h"
#include "client.h" #include "client.h"
#include "component.h"
#include "message.h" #include "message.h"
class WebsocketsDispatcher : public SurfaceComponent class WebsocketsDispatcher : public SurfaceComponent
{ {
public:
WebsocketsDispatcher (ArdourSurface::ArdourWebsockets& surface)
: SurfaceComponent (surface){};
virtual ~WebsocketsDispatcher (){};
public: void dispatch (Client, const NodeStateMessage&);
void update_all_nodes (Client);
WebsocketsDispatcher (ArdourSurface::ArdourWebsockets& surface) : SurfaceComponent (surface) {}; private:
virtual ~WebsocketsDispatcher () {}; typedef void (WebsocketsDispatcher::*DispatcherMethod) (Client, const NodeStateMessage&);
typedef boost::unordered_map<std::string, DispatcherMethod> NodeMethodMap;
void dispatch (Client, const NodeStateMessage&);
void update_all_nodes (Client);
private: static NodeMethodMap _node_to_method;
typedef void (WebsocketsDispatcher::*DispatcherMethod) (Client, const NodeStateMessage&); void tempo_handler (Client, const NodeStateMessage&);
typedef boost::unordered_map<std::string, DispatcherMethod> NodeMethodMap; void strip_gain_handler (Client, const NodeStateMessage&);
void strip_pan_handler (Client, const NodeStateMessage&);
static NodeMethodMap _node_to_method; void strip_mute_handler (Client, const NodeStateMessage&);
void strip_plugin_enable_handler (Client, const NodeStateMessage&);
void tempo_handler (Client, const NodeStateMessage&); void strip_plugin_param_value_handler (Client, const NodeStateMessage&);
void strip_gain_handler (Client, const NodeStateMessage&);
void strip_pan_handler (Client, const NodeStateMessage&);
void strip_mute_handler (Client, const NodeStateMessage&);
void strip_plugin_enable_handler (Client, const NodeStateMessage&);
void strip_plugin_param_value_handler (Client, const NodeStateMessage&);
void update (Client, std::string, TypedValue);
void update (Client, std::string, uint32_t, TypedValue);
void update (Client, std::string, uint32_t, uint32_t, TypedValue);
void update (Client, std::string, uint32_t, uint32_t, uint32_t, TypedValue);
void update (Client, std::string, const AddressVector&, const ValueVector&);
void update (Client, std::string, TypedValue);
void update (Client, std::string, uint32_t, TypedValue);
void update (Client, std::string, uint32_t, uint32_t, TypedValue);
void update (Client, std::string, uint32_t, uint32_t, uint32_t, TypedValue);
void update (Client, std::string, const AddressVector&, const ValueVector&);
}; };
#endif // websockets_dispatcher_h #endif // websockets_dispatcher_h

View file

@ -16,205 +16,212 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "ardour/meter.h"
#include "ardour/plugin_insert.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/tempo.h" #include "ardour/tempo.h"
#include "ardour/plugin_insert.h"
#include "ardour/meter.h"
#include "feedback.h" #include "feedback.h"
#include "strips.h"
#include "globals.h" #include "globals.h"
#include "state.h"
#include "server.h" #include "server.h"
#include "state.h"
#include "strips.h"
using namespace ARDOUR; using namespace ARDOUR;
struct TempoObserver { struct TempoObserver {
void operator() (ArdourFeedback* p) { void operator() (ArdourFeedback* p)
p->update_all (Node::tempo, p->globals ().tempo ()); {
} p->update_all (Node::tempo, p->globals ().tempo ());
}
}; };
struct StripGainObserver { struct StripGainObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n) { 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->strips ().strip_gain (strip_n)); // fires multiple times (4x as of ardour 6.0)
} p->update_all (Node::strip_gain, strip_n, p->strips ().strip_gain (strip_n));
}
}; };
struct StripPanObserver { struct StripPanObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n) { void operator() (ArdourFeedback* p, uint32_t strip_n)
p->update_all (Node::strip_pan, strip_n, p->strips ().strip_pan (strip_n)); {
} p->update_all (Node::strip_pan, strip_n, p->strips ().strip_pan (strip_n));
}
}; };
struct StripMuteObserver { struct StripMuteObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n) { void operator() (ArdourFeedback* p, uint32_t strip_n)
p->update_all (Node::strip_mute, strip_n, p->strips ().strip_mute (strip_n)); {
} p->update_all (Node::strip_mute, strip_n, p->strips ().strip_mute (strip_n));
}
}; };
struct PluginBypassObserver { struct PluginBypassObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n, uint32_t plugin_n) { void operator() (ArdourFeedback* p, uint32_t strip_n, uint32_t plugin_n)
p->update_all (Node::strip_plugin_enable, strip_n, plugin_n, {
p->strips ().strip_plugin_enabled (strip_n, plugin_n)); p->update_all (Node::strip_plugin_enable, strip_n, plugin_n,
} p->strips ().strip_plugin_enabled (strip_n, plugin_n));
}
}; };
struct PluginParamValueObserver { struct PluginParamValueObserver {
void operator() (ArdourFeedback* p, uint32_t strip_n, uint32_t plugin_n, void operator() (ArdourFeedback* p, uint32_t strip_n, uint32_t plugin_n,
uint32_t param_n, boost::shared_ptr<AutomationControl> control) { uint32_t param_n, boost::shared_ptr<AutomationControl> control)
p->update_all (Node::strip_plugin_param_value, strip_n, plugin_n, param_n, {
ArdourStrips::plugin_param_value (control)); p->update_all (Node::strip_plugin_param_value, strip_n, plugin_n, param_n,
} ArdourStrips::plugin_param_value (control));
}
}; };
int int
ArdourFeedback::start () ArdourFeedback::start ()
{ {
observe_globals (); observe_globals ();
observe_strips (); observe_strips ();
// some things need polling like the strip meters // some things need polling like the strip meters
Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // ms Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (100); // ms
_periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, _periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this,
&ArdourFeedback::poll)); &ArdourFeedback::poll));
periodic_timeout->attach (main_loop ()->get_context ()); periodic_timeout->attach (main_loop ()->get_context ());
return 0; return 0;
} }
int int
ArdourFeedback::stop () ArdourFeedback::stop ()
{ {
_periodic_connection.disconnect (); _periodic_connection.disconnect ();
_signal_connections.drop_connections (); _signal_connections.drop_connections ();
return 0; return 0;
} }
void void
ArdourFeedback::update_all (std::string node, TypedValue value) const ArdourFeedback::update_all (std::string node, TypedValue value) const
{ {
update_all (node, ADDR_NONE, ADDR_NONE, ADDR_NONE, value); update_all (node, ADDR_NONE, ADDR_NONE, ADDR_NONE, value);
} }
void void
ArdourFeedback::update_all (std::string node, uint32_t strip_n, TypedValue value) const ArdourFeedback::update_all (std::string node, uint32_t strip_n, TypedValue value) const
{ {
update_all (node, strip_n, ADDR_NONE, ADDR_NONE, value); update_all (node, strip_n, ADDR_NONE, ADDR_NONE, value);
} }
void void
ArdourFeedback::update_all (std::string node, uint32_t strip_n, uint32_t plugin_n, ArdourFeedback::update_all (std::string node, uint32_t strip_n, uint32_t plugin_n,
TypedValue value) const TypedValue value) const
{ {
update_all (node, strip_n, plugin_n, ADDR_NONE, value); update_all (node, strip_n, plugin_n, ADDR_NONE, value);
} }
void void
ArdourFeedback::update_all (std::string node, uint32_t strip_n, uint32_t plugin_n, uint32_t param_n, ArdourFeedback::update_all (std::string node, uint32_t strip_n, uint32_t plugin_n, uint32_t param_n,
TypedValue value) const TypedValue value) const
{ {
AddressVector addr = AddressVector (); AddressVector addr = AddressVector ();
if (strip_n != ADDR_NONE) { if (strip_n != ADDR_NONE) {
addr.push_back (strip_n); addr.push_back (strip_n);
} }
if (plugin_n != ADDR_NONE) { if (plugin_n != ADDR_NONE) {
addr.push_back (plugin_n); addr.push_back (plugin_n);
} }
if (param_n != ADDR_NONE) { if (param_n != ADDR_NONE) {
addr.push_back (param_n); addr.push_back (param_n);
} }
ValueVector val = ValueVector (); ValueVector val = ValueVector ();
val.push_back (value); val.push_back (value);
server ().update_all_clients (NodeState (node, addr, val), false); server ().update_all_clients (NodeState (node, addr, val), false);
} }
bool bool
ArdourFeedback::poll () const ArdourFeedback::poll () const
{ {
for (uint32_t strip_n = 0; strip_n < strips ().strip_count (); ++strip_n) { for (uint32_t strip_n = 0; strip_n < strips ().strip_count (); ++strip_n) {
// meters // meters
boost::shared_ptr<Stripable> strip = strips ().nth_strip (strip_n); boost::shared_ptr<Stripable> strip = strips ().nth_strip (strip_n);
boost::shared_ptr<PeakMeter> meter = strip->peak_meter (); boost::shared_ptr<PeakMeter> meter = strip->peak_meter ();
float db = meter ? meter->meter_level (0, MeterMCP) : -193; float db = meter ? meter->meter_level (0, MeterMCP) : -193;
update_all (Node::strip_meter, strip_n, static_cast<double>(db)); update_all (Node::strip_meter, strip_n, static_cast<double> (db));
} }
return true; return true;
} }
void void
ArdourFeedback::observe_globals () ArdourFeedback::observe_globals ()
{ {
session ().tempo_map ().PropertyChanged.connect (_signal_connections, MISSING_INVALIDATOR, session ().tempo_map ().PropertyChanged.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (TempoObserver (), this), event_loop ()); boost::bind<void> (TempoObserver (), this), event_loop ());
} }
void void
ArdourFeedback::observe_strips () ArdourFeedback::observe_strips ()
{ {
for (uint32_t strip_n = 0; strip_n < strips ().strip_count (); ++strip_n) { for (uint32_t strip_n = 0; strip_n < strips ().strip_count (); ++strip_n) {
boost::shared_ptr<Stripable> strip = strips ().nth_strip (strip_n); boost::shared_ptr<Stripable> strip = strips ().nth_strip (strip_n);
strip->gain_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR, strip->gain_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (StripGainObserver (), this, strip_n), event_loop ()); boost::bind<void> (StripGainObserver (), this, strip_n), event_loop ());
if (strip->pan_azimuth_control ()) { if (strip->pan_azimuth_control ()) {
strip->pan_azimuth_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR, strip->pan_azimuth_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (StripPanObserver (), this, strip_n), event_loop ()); boost::bind<void> (StripPanObserver (), this, strip_n), event_loop ());
}
strip->mute_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (StripMuteObserver (), this, strip_n), event_loop ());
observe_strip_plugins (strip_n, strip);
} }
strip->mute_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (StripMuteObserver (), this, strip_n), event_loop ());
observe_strip_plugins (strip_n, strip);
}
} }
void void
ArdourFeedback::observe_strip_plugins (uint32_t strip_n, boost::shared_ptr<ARDOUR::Stripable> strip) ArdourFeedback::observe_strip_plugins (uint32_t strip_n, boost::shared_ptr<ARDOUR::Stripable> strip)
{ {
for (uint32_t plugin_n = 0 ; ; ++plugin_n) { for (uint32_t plugin_n = 0;; ++plugin_n) {
boost::shared_ptr<PluginInsert> insert = strips ().strip_plugin_insert (strip_n, plugin_n); boost::shared_ptr<PluginInsert> insert = strips ().strip_plugin_insert (strip_n, plugin_n);
if (!insert) { if (!insert) {
break; break;
} }
uint32_t bypass = insert->plugin ()->designated_bypass_port (); uint32_t bypass = insert->plugin ()->designated_bypass_port ();
Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass); Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass);
boost::shared_ptr<AutomationControl> control = insert->automation_control (param); boost::shared_ptr<AutomationControl> control = insert->automation_control (param);
if (control) { if (control) {
control->Changed.connect (_signal_connections, MISSING_INVALIDATOR, control->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (PluginBypassObserver (), this, strip_n, plugin_n), event_loop ()); boost::bind<void> (PluginBypassObserver (), this, strip_n, plugin_n), event_loop ());
} }
observe_strip_plugin_param_values (strip_n, plugin_n, insert); observe_strip_plugin_param_values (strip_n, plugin_n, insert);
} }
} }
void void
ArdourFeedback::observe_strip_plugin_param_values (uint32_t strip_n, ArdourFeedback::observe_strip_plugin_param_values (uint32_t strip_n,
uint32_t plugin_n, boost::shared_ptr<ARDOUR::PluginInsert> insert) uint32_t plugin_n, boost::shared_ptr<ARDOUR::PluginInsert> insert)
{ {
boost::shared_ptr<Plugin> plugin = insert->plugin (); boost::shared_ptr<Plugin> plugin = insert->plugin ();
for (uint32_t param_n = 0; param_n < plugin->parameter_count (); ++param_n) { for (uint32_t param_n = 0; param_n < plugin->parameter_count (); ++param_n) {
boost::shared_ptr<AutomationControl> control = strips ().strip_plugin_param_control ( boost::shared_ptr<AutomationControl> control = strips ().strip_plugin_param_control (
strip_n, plugin_n, param_n); strip_n, plugin_n, param_n);
if (!control) { if (!control) {
continue; continue;
} }
control->Changed.connect (_signal_connections, MISSING_INVALIDATOR, control->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
boost::bind<void> (PluginParamValueObserver (), this, strip_n, plugin_n, param_n, boost::bind<void> (PluginParamValueObserver (), this, strip_n, plugin_n, param_n,
control), event_loop ()); control),
} event_loop ());
}
} }

View file

@ -19,41 +19,39 @@
#ifndef ardour_feedback_h #ifndef ardour_feedback_h
#define ardour_feedback_h #define ardour_feedback_h
#include <glibmm/main.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <glibmm/main.h>
#include "component.h" #include "component.h"
#include "typed_value.h" #include "typed_value.h"
class ArdourFeedback : public SurfaceComponent class ArdourFeedback : public SurfaceComponent
{ {
public: public:
ArdourFeedback (ArdourSurface::ArdourWebsockets& surface)
: SurfaceComponent (surface){};
virtual ~ArdourFeedback (){};
ArdourFeedback (ArdourSurface::ArdourWebsockets& surface) : SurfaceComponent (surface) {}; int start ();
virtual ~ArdourFeedback () {}; int stop ();
int start (); void update_all (std::string, TypedValue) const;
int stop (); void update_all (std::string, uint32_t, TypedValue) const;
void update_all (std::string, uint32_t, uint32_t, TypedValue) const;
void update_all (std::string, uint32_t, uint32_t, uint32_t, TypedValue) const;
void update_all (std::string, TypedValue) const; private:
void update_all (std::string, uint32_t, TypedValue) const; Glib::Threads::Mutex _client_state_lock;
void update_all (std::string, uint32_t, uint32_t, TypedValue) const; PBD::ScopedConnectionList _signal_connections;
void update_all (std::string, uint32_t, uint32_t, uint32_t, TypedValue) const; sigc::connection _periodic_connection;
private:
Glib::Threads::Mutex _client_state_lock; bool poll () const;
PBD::ScopedConnectionList _signal_connections;
sigc::connection _periodic_connection;
bool poll () const;
void observe_globals ();
void observe_strips ();
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_globals ();
void observe_strips ();
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>);
}; };
#endif // ardour_feedback_h #endif // ardour_feedback_h

View file

@ -25,15 +25,15 @@ using namespace ARDOUR;
double double
ArdourGlobals::tempo () const ArdourGlobals::tempo () const
{ {
Tempo tempo = session ().tempo_map ().tempo_at_sample (0); Tempo tempo = session ().tempo_map ().tempo_at_sample (0);
return tempo.note_type () * tempo.pulses_per_minute (); return tempo.note_type () * tempo.pulses_per_minute ();
} }
void void
ArdourGlobals::set_tempo (double bpm) ArdourGlobals::set_tempo (double bpm)
{ {
bpm = max (0.01, bpm); bpm = max (0.01, bpm);
TempoMap& tempo_map = session ().tempo_map (); TempoMap& tempo_map = session ().tempo_map ();
Tempo tempo (bpm, tempo_map.tempo_at_sample (0).note_type (), bpm); Tempo tempo (bpm, tempo_map.tempo_at_sample (0).note_type (), bpm);
tempo_map.add_tempo (tempo, 0.0, 0, AudioTime); tempo_map.add_tempo (tempo, 0.0, 0, AudioTime);
} }

View file

@ -23,14 +23,13 @@
class ArdourGlobals : public SurfaceComponent class ArdourGlobals : public SurfaceComponent
{ {
public: public:
ArdourGlobals (ArdourSurface::ArdourWebsockets& surface)
ArdourGlobals (ArdourSurface::ArdourWebsockets& surface) : SurfaceComponent (surface) {}; : SurfaceComponent (surface){};
virtual ~ArdourGlobals () {}; virtual ~ArdourGlobals (){};
double tempo () const;
void set_tempo (double);
double tempo () const;
void set_tempo (double);
}; };
#endif // ardour_globals_h #endif // ardour_globals_h

View file

@ -27,47 +27,49 @@ using namespace ArdourSurface;
static ControlProtocol* static ControlProtocol*
new_ardour_websockets_protocol (ControlProtocolDescriptor* /*descriptor*/, new_ardour_websockets_protocol (ControlProtocolDescriptor* /*descriptor*/,
Session* s) Session* s)
{ {
ArdourWebsockets* surface = new ArdourWebsockets (*s); ArdourWebsockets* surface = new ArdourWebsockets (*s);
surface->set_active (true); surface->set_active (true);
return surface; return surface;
} }
static void static void
delete_ardour_websockets_protocol (ControlProtocolDescriptor* /*descriptor*/, delete_ardour_websockets_protocol (ControlProtocolDescriptor* /*descriptor*/,
ControlProtocol* cp) ControlProtocol* cp)
{ {
delete cp; delete cp;
} }
static bool static bool
probe_ardour_websockets_protocol (ControlProtocolDescriptor* /*descriptor*/) probe_ardour_websockets_protocol (ControlProtocolDescriptor* /*descriptor*/)
{ {
return true; return true;
} }
static void* static void*
ardour_websockets_request_buffer_factory (uint32_t num_requests) ardour_websockets_request_buffer_factory (uint32_t num_requests)
{ {
return ArdourWebsockets::request_factory (num_requests); return ArdourWebsockets::request_factory (num_requests);
} }
static ControlProtocolDescriptor ardour_websockets_descriptor = { static ControlProtocolDescriptor ardour_websockets_descriptor = {
/*name : */ SURFACE_NAME, /*name : */ SURFACE_NAME,
/*id : */ SURFACE_ID, /*id : */ SURFACE_ID,
/*ptr : */ 0, /*ptr : */ 0,
/*module : */ 0, /*module : */ 0,
/*mandatory : */ 0, /*mandatory : */ 0,
/*supports_feedback : */ true, /*supports_feedback : */ true,
/*probe : */ probe_ardour_websockets_protocol, /*probe : */ probe_ardour_websockets_protocol,
/*initialize : */ new_ardour_websockets_protocol, /*initialize : */ new_ardour_websockets_protocol,
/*destroy : */ delete_ardour_websockets_protocol, /*destroy : */ delete_ardour_websockets_protocol,
/*request_buffer_factory */ ardour_websockets_request_buffer_factory /*request_buffer_factory */ ardour_websockets_request_buffer_factory
}; };
extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { extern "C" ARDOURSURFACE_API ControlProtocolDescriptor*
return &ardour_websockets_descriptor; protocol_descriptor ()
{
return &ardour_websockets_descriptor;
} }

View file

@ -20,18 +20,18 @@
#include <iostream> #include <iostream>
#endif #endif
#include <sstream>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <sstream>
#include "message.h" #include "message.h"
// JSON does not support Infinity or NaN // JSON does not support Infinity or NaN
#define XSTR(s) STR(s) #define XSTR(s) STR (s)
#define STR(s) #s #define STR(s) #s
#define JSON_INF 1.0e+128 #define JSON_INF 1.0e+128
#define JSON_INF_STR XSTR(JSON_INF) #define JSON_INF_STR XSTR (JSON_INF)
namespace pt = boost::property_tree; namespace pt = boost::property_tree;
@ -39,155 +39,154 @@ NodeStateMessage::NodeStateMessage (const NodeState& state)
: _valid (true) : _valid (true)
, _state (state) , _state (state)
{ {
_write = state.n_val () > 0; _write = state.n_val () > 0;
} }
NodeStateMessage::NodeStateMessage (void *buf, size_t len) NodeStateMessage::NodeStateMessage (void* buf, size_t len)
: _valid (false) : _valid (false)
, _write (false) , _write (false)
{ {
try { try {
std::string s (static_cast<char *>(buf), len); std::string s (static_cast<char*> (buf), len);
std::istringstream is (s); std::istringstream is (s);
pt::ptree root; pt::ptree root;
pt::read_json (is, root); pt::read_json (is, root);
_state = NodeState (root.get<std::string> ("node")); _state = NodeState (root.get<std::string> ("node"));
pt::ptree addr = root.get_child ("addr", pt::ptree ()); pt::ptree addr = root.get_child ("addr", pt::ptree ());
for (pt::ptree::iterator it = addr.begin (); it != addr.end (); ++it) { for (pt::ptree::iterator it = addr.begin (); it != addr.end (); ++it) {
// throws if datatype not uint32_t // throws if datatype not uint32_t
_state.add_addr (boost::lexical_cast<uint32_t>(it->second.data ())); _state.add_addr (boost::lexical_cast<uint32_t> (it->second.data ()));
} }
pt::ptree val = root.get_child ("val", pt::ptree ()); pt::ptree val = root.get_child ("val", pt::ptree ());
for (pt::ptree::iterator it = val.begin (); it != val.end (); ++it) { for (pt::ptree::iterator it = val.begin (); it != val.end (); ++it) {
std::string val = it->second.data ();
std::string val = it->second.data (); try {
_state.add_val (boost::lexical_cast<int> (val));
} catch (const boost::bad_lexical_cast&) {
try {
double d = boost::lexical_cast<double> (val);
if (d >= JSON_INF) {
d = std::numeric_limits<double>::infinity ();
} else if (d <= -JSON_INF) {
d = -std::numeric_limits<double>::infinity ();
}
_state.add_val (d);
} catch (const boost::bad_lexical_cast&) {
if (val == "false") {
_state.add_val (false);
} else if (val == "true") {
_state.add_val (true);
} else {
_state.add_val (val);
}
}
}
}
try { if (_state.n_val () > 0) {
_state.add_val (boost::lexical_cast<int>(val)); _write = true;
} catch (const boost::bad_lexical_cast&) { }
try {
double d = boost::lexical_cast<double>(val);
if (d >= JSON_INF) {
d = std::numeric_limits<double>::infinity ();
} else if (d <= -JSON_INF) {
d = -std::numeric_limits<double>::infinity ();
}
_state.add_val (d);
} catch (const boost::bad_lexical_cast&) {
if (val == "false") {
_state.add_val (false);
} else if (val == "true") {
_state.add_val (true);
} else {
_state.add_val (val);
}
}
}
}
if (_state.n_val () > 0) { _valid = true;
_write = true;
}
_valid = true; } catch (const std::exception& exc) {
} catch (const std::exception& exc) {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "cannot parse message - " << exc.what () << std::endl; std::cerr << "cannot parse message - " << exc.what () << std::endl;
#endif #endif
} }
} }
size_t size_t
NodeStateMessage::serialize (void *buf, size_t len) const NodeStateMessage::serialize (void* buf, size_t len) const
{ {
// boost json writes all values as strings, we do not want that // boost json writes all values as strings, we do not want that
if (len == 0) { if (len == 0) {
return -1; return -1;
} }
std::stringstream ss; std::stringstream ss;
ss << "{\"node\":\"" << _state.node () << "\""; ss << "{\"node\":\"" << _state.node () << "\"";
int n_addr = _state.n_addr (); int n_addr = _state.n_addr ();
if (n_addr > 0) { if (n_addr > 0) {
ss << ",\"addr\":["; ss << ",\"addr\":[";
for (int i = 0; i < n_addr; i++) { for (int i = 0; i < n_addr; i++) {
if (i > 0) { if (i > 0) {
ss << ','; ss << ',';
} }
ss << _state.nth_addr (i); ss << _state.nth_addr (i);
} }
ss << "]"; ss << "]";
} }
int n_val = _state.n_val (); int n_val = _state.n_val ();
if (n_val > 0) { if (n_val > 0) {
ss << ",\"val\":["; ss << ",\"val\":[";
for (int i = 0; i < n_val; i++) { for (int i = 0; i < n_val; i++) {
if (i > 0) { if (i > 0) {
ss << ','; ss << ',';
} }
TypedValue val = _state.nth_val (i); TypedValue val = _state.nth_val (i);
switch (val.type ()) { switch (val.type ()) {
case TypedValue::Empty: case TypedValue::Empty:
ss << "null"; ss << "null";
break; break;
case TypedValue::Bool: case TypedValue::Bool:
ss << (static_cast<bool>(val) ? "true" : "false"); ss << (static_cast<bool> (val) ? "true" : "false");
break; break;
case TypedValue::Int: case TypedValue::Int:
ss << static_cast<int>(val); ss << static_cast<int> (val);
break; break;
case TypedValue::Double: { case TypedValue::Double: {
double d = static_cast<double>(val); double d = static_cast<double> (val);
if (d == std::numeric_limits<double>::infinity ()) { if (d == std::numeric_limits<double>::infinity ()) {
ss << JSON_INF_STR; ss << JSON_INF_STR;
} else if (d == -std::numeric_limits<double>::infinity ()) { } else if (d == -std::numeric_limits<double>::infinity ()) {
ss << "-" JSON_INF_STR; ss << "-" JSON_INF_STR;
} else { } else {
ss << d; ss << d;
} }
break; break;
} }
case TypedValue::String: case TypedValue::String:
ss << '"' << static_cast<std::string>(val) << '"'; ss << '"' << static_cast<std::string> (val) << '"';
break; break;
default: default:
break; break;
} }
} }
ss << "]"; ss << "]";
} }
ss << '}'; ss << '}';
std::string s = ss.str (); std::string s = ss.str ();
const char *cs = s.c_str (); const char* cs = s.c_str ();
size_t cs_sz = strlen (cs); size_t cs_sz = strlen (cs);
if (len < cs_sz) { if (len < cs_sz) {
return -1; return -1;
} }
memcpy (buf, cs, cs_sz); memcpy (buf, cs, cs_sz);
return cs_sz; return cs_sz;
} }

View file

@ -23,23 +23,29 @@
class NodeStateMessage class NodeStateMessage
{ {
public: public:
NodeStateMessage (const NodeState& state);
NodeStateMessage (void*, size_t);
NodeStateMessage (const NodeState& state); size_t serialize (void*, size_t) const;
NodeStateMessage (void *, size_t);
size_t serialize (void *, size_t) const; bool is_valid () const
{
bool is_valid () const { return _valid; } return _valid;
bool is_write () const { return _write; } }
const NodeState& state () const { return _state; } bool is_write () const
{
private: return _write;
}
bool _valid; const NodeState& state () const
bool _write; {
NodeState _state; return _state;
}
private:
bool _valid;
bool _write;
NodeState _state;
}; };
#endif // websockets_message_h #endif // websockets_message_h

View file

@ -20,22 +20,22 @@
#include <iostream> #include <iostream>
#endif #endif
#include "server.h"
#include "dispatcher.h" #include "dispatcher.h"
#include "server.h"
/* backport from libwebsockets 3.0, /* backport from libwebsockets 3.0,
* allow to compile on GNU/Linux with libwebsockets 2.x * allow to compile on GNU/Linux with libwebsockets 2.x
*/ */
#ifndef PLATFORM_WINDOWS #ifndef PLATFORM_WINDOWS
# ifndef LWS_POLLHUP #ifndef LWS_POLLHUP
# define LWS_POLLHUP (POLLHUP|POLLERR) #define LWS_POLLHUP (POLLHUP | POLLERR)
# endif #endif
# ifndef LWS_POLLIN #ifndef LWS_POLLIN
# define LWS_POLLIN (POLLIN) #define LWS_POLLIN (POLLIN)
# endif #endif
# ifndef LWS_POLLOUT #ifndef LWS_POLLOUT
# define LWS_POLLOUT (POLLOUT) #define LWS_POLLOUT (POLLOUT)
# endif #endif
#endif #endif
using namespace Glib; using namespace Glib;
@ -44,350 +44,353 @@ WebsocketsServer::WebsocketsServer (ArdourSurface::ArdourWebsockets& surface)
: SurfaceComponent (surface) : SurfaceComponent (surface)
, _lws_context (0) , _lws_context (0)
{ {
// keep references to all config for libwebsockets 2 /* keep references to all config for libwebsockets 2 */
lws_protocols proto; lws_protocols proto;
memset (&proto, 0, sizeof(lws_protocols)); memset (&proto, 0, sizeof (lws_protocols));
proto.name = "lws-ardour"; proto.name = "lws-ardour";
proto.callback = WebsocketsServer::lws_callback; proto.callback = WebsocketsServer::lws_callback;
proto.per_session_data_size = 0; proto.per_session_data_size = 0;
proto.rx_buffer_size = 0; proto.rx_buffer_size = 0;
proto.id = 0; proto.id = 0;
proto.user = 0; proto.user = 0;
#if LWS_LIBRARY_VERSION_MAJOR >= 3 #if LWS_LIBRARY_VERSION_MAJOR >= 3
proto.tx_packet_size = 0; proto.tx_packet_size = 0;
#endif #endif
_lws_proto[0] = proto; _lws_proto[0] = proto;
memset (&_lws_proto[1], 0, sizeof(lws_protocols)); memset (&_lws_proto[1], 0, sizeof (lws_protocols));
memset (&_lws_info, 0, sizeof(lws_context_creation_info)); memset (&_lws_info, 0, sizeof (lws_context_creation_info));
_lws_info.port = WEBSOCKET_LISTEN_PORT; _lws_info.port = WEBSOCKET_LISTEN_PORT;
_lws_info.protocols = _lws_proto; _lws_info.protocols = _lws_proto;
_lws_info.uid = -1; _lws_info.uid = -1;
_lws_info.gid = -1; _lws_info.gid = -1;
_lws_info.user = this; _lws_info.user = this;
} }
int int
WebsocketsServer::start () WebsocketsServer::start ()
{ {
_lws_context = lws_create_context (&_lws_info); _lws_context = lws_create_context (&_lws_info);
if (!_lws_context) { if (!_lws_context) {
PBD::error << "ArdourWebsockets: could not create libwebsockets context" << endmsg; PBD::error << "ArdourWebsockets: could not create libwebsockets context" << endmsg;
return -1; return -1;
} }
// add_poll_fd() should have been called once during lws_create_context() /* add_poll_fd() should have been called once during lws_create_context()
// if _fd_ctx is empty then LWS_CALLBACK_ADD_POLL_FD was not called * if _fd_ctx is empty then LWS_CALLBACK_ADD_POLL_FD was not called
// this means libwesockets was not compiled with LWS_WITH_EXTERNAL_POLL * this means libwesockets was not compiled with LWS_WITH_EXTERNAL_POLL
// - macos homebrew libwebsockets: disabled (3.2.2 as of Feb 2020) * - macos homebrew libwebsockets: disabled (3.2.2 as of Feb 2020)
// - linux ubuntu libwebsockets-dev: enabled (2.0.3 as of Feb 2020) but * - linux ubuntu libwebsockets-dev: enabled (2.0.3 as of Feb 2020) but
// #if defined(LWS_WITH_EXTERNAL_POLL) check is not reliable -- constant * #if defined(LWS_WITH_EXTERNAL_POLL) check is not reliable -- constant
// missing from /usr/include/lws_config.h * missing from /usr/include/lws_config.h
*/
if (_fd_ctx.empty ()) { if (_fd_ctx.empty ()) {
PBD::error << "ArdourWebsockets: check your libwebsockets was compiled" PBD::error << "ArdourWebsockets: check your libwebsockets was compiled"
" with LWS_WITH_EXTERNAL_POLL enabled" << endmsg; " with LWS_WITH_EXTERNAL_POLL enabled"
return -1; << endmsg;
} return -1;
}
return 0; return 0;
} }
int int
WebsocketsServer::stop () WebsocketsServer::stop ()
{ {
for (LwsPollFdGlibSourceMap::iterator it = _fd_ctx.begin (); it != _fd_ctx.end (); ++it) { for (LwsPollFdGlibSourceMap::iterator it = _fd_ctx.begin (); it != _fd_ctx.end (); ++it) {
it->second.rg_iosrc->destroy (); it->second.rg_iosrc->destroy ();
if (it->second.wg_iosrc) { if (it->second.wg_iosrc) {
it->second.wg_iosrc->destroy (); it->second.wg_iosrc->destroy ();
} }
} }
_fd_ctx.clear (); _fd_ctx.clear ();
if (_lws_context) { if (_lws_context) {
lws_context_destroy (_lws_context); lws_context_destroy (_lws_context);
_lws_context = 0; _lws_context = 0;
} }
return 0; return 0;
} }
void void
WebsocketsServer::update_client (Client wsi, const NodeState& state, bool force) WebsocketsServer::update_client (Client wsi, const NodeState& state, bool force)
{ {
ClientContextMap::iterator it = _client_ctx.find (wsi); ClientContextMap::iterator it = _client_ctx.find (wsi);
if (it == _client_ctx.end ()) { if (it == _client_ctx.end ()) {
return; return;
} }
if (force || !it->second.has_state (state)) { if (force || !it->second.has_state (state)) {
// write to client only if state was updated /* write to client only if state was updated */
it->second.update_state (state); it->second.update_state (state);
it->second.output_buf ().push_back (NodeStateMessage (state)); it->second.output_buf ().push_back (NodeStateMessage (state));
lws_callback_on_writable (wsi); lws_callback_on_writable (wsi);
} }
} }
void void
WebsocketsServer::update_all_clients (const NodeState& state, bool force) WebsocketsServer::update_all_clients (const NodeState& state, bool force)
{ {
for (ClientContextMap::iterator it = _client_ctx.begin (); it != _client_ctx.end (); ++it) { for (ClientContextMap::iterator it = _client_ctx.begin (); it != _client_ctx.end (); ++it) {
update_client (it->second.wsi (), state, force); update_client (it->second.wsi (), state, force);
} }
} }
void void
WebsocketsServer::add_poll_fd (struct lws_pollargs *pa) WebsocketsServer::add_poll_fd (struct lws_pollargs* pa)
{ {
// fd can be SOCKET or int depending platform /* fd can be SOCKET or int depending platform */
lws_sockfd_type fd = pa->fd; lws_sockfd_type fd = pa->fd;
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
RefPtr<IOChannel> g_channel = IOChannel::create_from_win32_socket (fd); RefPtr<IOChannel> g_channel = IOChannel::create_from_win32_socket (fd);
#else #else
RefPtr<IOChannel> g_channel = IOChannel::create_from_fd (fd); RefPtr<IOChannel> g_channel = IOChannel::create_from_fd (fd);
#endif #endif
RefPtr<IOSource> rg_iosrc (IOSource::create (g_channel, events_to_ioc (pa->events))); RefPtr<IOSource> rg_iosrc (IOSource::create (g_channel, events_to_ioc (pa->events)));
rg_iosrc->connect (sigc::bind (sigc::mem_fun (*this, &WebsocketsServer::io_handler), fd)); rg_iosrc->connect (sigc::bind (sigc::mem_fun (*this, &WebsocketsServer::io_handler), fd));
rg_iosrc->attach (main_loop ()->get_context ()); rg_iosrc->attach (main_loop ()->get_context ());
struct lws_pollfd lws_pfd; struct lws_pollfd lws_pfd;
lws_pfd.fd = pa->fd; lws_pfd.fd = pa->fd;
lws_pfd.events = pa->events; lws_pfd.events = pa->events;
lws_pfd.revents = 0; lws_pfd.revents = 0;
LwsPollFdGlibSource ctx; LwsPollFdGlibSource ctx;
ctx.lws_pfd = lws_pfd; ctx.lws_pfd = lws_pfd;
ctx.g_channel = g_channel; ctx.g_channel = g_channel;
ctx.rg_iosrc = rg_iosrc; ctx.rg_iosrc = rg_iosrc;
ctx.wg_iosrc = Glib::RefPtr<Glib::IOSource>(0); ctx.wg_iosrc = Glib::RefPtr<Glib::IOSource> (0);
_fd_ctx[fd] = ctx; _fd_ctx[fd] = ctx;
} }
void void
WebsocketsServer::mod_poll_fd (struct lws_pollargs *pa) WebsocketsServer::mod_poll_fd (struct lws_pollargs* pa)
{ {
LwsPollFdGlibSourceMap::iterator it = _fd_ctx.find (pa->fd); LwsPollFdGlibSourceMap::iterator it = _fd_ctx.find (pa->fd);
if (it == _fd_ctx.end ()) { if (it == _fd_ctx.end ()) {
return; return;
} }
it->second.lws_pfd.events = pa->events; it->second.lws_pfd.events = pa->events;
if (pa->events & LWS_POLLOUT) { if (pa->events & LWS_POLLOUT) {
// libwebsockets wants to write but cannot find a way to update /* libwebsockets wants to write but cannot find a way to update
// an existing glib::iosource event flags using glibmm, * an existing glib::iosource event flags using glibmm,
// create another iosource and set to IO_OUT, it will be destroyed * create another iosource and set to IO_OUT, it will be destroyed
// after clearing POLLOUT (see 'else' body below) * after clearing POLLOUT (see 'else' body below)
*/
if (it->second.wg_iosrc) { if (it->second.wg_iosrc) {
// already polling for write /* already polling for write */
return; return;
} }
RefPtr<IOSource> wg_iosrc = it->second.g_channel->create_watch (Glib::IO_OUT); RefPtr<IOSource> wg_iosrc = it->second.g_channel->create_watch (Glib::IO_OUT);
wg_iosrc->connect (sigc::bind (sigc::mem_fun (*this, &WebsocketsServer::io_handler), pa->fd)); wg_iosrc->connect (sigc::bind (sigc::mem_fun (*this, &WebsocketsServer::io_handler), pa->fd));
wg_iosrc->attach (main_loop ()->get_context ()); wg_iosrc->attach (main_loop ()->get_context ());
it->second.wg_iosrc = wg_iosrc; it->second.wg_iosrc = wg_iosrc;
} else { } else {
if (it->second.wg_iosrc) { if (it->second.wg_iosrc) {
it->second.wg_iosrc->destroy (); it->second.wg_iosrc->destroy ();
it->second.wg_iosrc = Glib::RefPtr<Glib::IOSource>(0); it->second.wg_iosrc = Glib::RefPtr<Glib::IOSource> (0);
} }
} }
} }
void void
WebsocketsServer::del_poll_fd (struct lws_pollargs *pa) WebsocketsServer::del_poll_fd (struct lws_pollargs* pa)
{ {
LwsPollFdGlibSourceMap::iterator it = _fd_ctx.find (pa->fd); LwsPollFdGlibSourceMap::iterator it = _fd_ctx.find (pa->fd);
if (it == _fd_ctx.end ()) { if (it == _fd_ctx.end ()) {
return; return;
} }
it->second.rg_iosrc->destroy (); it->second.rg_iosrc->destroy ();
if (it->second.wg_iosrc) { if (it->second.wg_iosrc) {
it->second.wg_iosrc->destroy (); it->second.wg_iosrc->destroy ();
} }
_fd_ctx.erase (it); _fd_ctx.erase (it);
} }
void void
WebsocketsServer::add_client (Client wsi) WebsocketsServer::add_client (Client wsi)
{ {
_client_ctx.emplace (wsi, ClientContext (wsi)); _client_ctx.emplace (wsi, ClientContext (wsi));
dispatcher ().update_all_nodes (wsi); // send all state dispatcher ().update_all_nodes (wsi); // send all state
} }
void void
WebsocketsServer::del_client (Client wsi) WebsocketsServer::del_client (Client wsi)
{ {
ClientContextMap::iterator it = _client_ctx.find (wsi); ClientContextMap::iterator it = _client_ctx.find (wsi);
if (it != _client_ctx.end ()) { if (it != _client_ctx.end ()) {
_client_ctx.erase (it); _client_ctx.erase (it);
} }
} }
void void
WebsocketsServer::recv_client (Client wsi, void *buf, size_t len) WebsocketsServer::recv_client (Client wsi, void* buf, size_t len)
{ {
NodeStateMessage msg (buf, len); NodeStateMessage msg (buf, len);
if (!msg.is_valid ()) { if (!msg.is_valid ()) {
return; return;
} }
#ifdef DEBUG #ifdef DEBUG
std::cerr << "RX " << msg.state ().debug_str () << std::endl; std::cerr << "RX " << msg.state ().debug_str () << std::endl;
#endif #endif
ClientContextMap::iterator it = _client_ctx.find (wsi); ClientContextMap::iterator it = _client_ctx.find (wsi);
if (it == _client_ctx.end ()) { if (it == _client_ctx.end ()) {
return; return;
} }
// avoid echo /* avoid echo */
it->second.update_state (msg.state ()); it->second.update_state (msg.state ());
dispatcher ().dispatch (wsi, msg); dispatcher ().dispatch (wsi, msg);
} }
void void
WebsocketsServer::write_client (Client wsi) WebsocketsServer::write_client (Client wsi)
{ {
ClientContextMap::iterator it = _client_ctx.find (wsi); ClientContextMap::iterator it = _client_ctx.find (wsi);
if (it == _client_ctx.end ()) { if (it == _client_ctx.end ()) {
return; return;
} }
ClientOutputBuffer& pending = it->second.output_buf (); ClientOutputBuffer& pending = it->second.output_buf ();
if (pending.empty ()) { if (pending.empty ()) {
return; return;
} }
// one lws_write() call per LWS_CALLBACK_SERVER_WRITEABLE callback /* one lws_write() call per LWS_CALLBACK_SERVER_WRITEABLE callback */
NodeStateMessage msg = pending.front (); NodeStateMessage msg = pending.front ();
pending.pop_front (); pending.pop_front ();
unsigned char out_buf[1024]; unsigned char out_buf[1024];
size_t len = msg.serialize (out_buf + LWS_PRE, 1024 - LWS_PRE); size_t len = msg.serialize (out_buf + LWS_PRE, 1024 - LWS_PRE);
if (len > 0) { if (len > 0) {
#ifdef DEBUG #ifdef DEBUG
std::cerr << "TX " << msg.state ().debug_str () << std::endl; std::cerr << "TX " << msg.state ().debug_str () << std::endl;
#endif #endif
lws_write (wsi, out_buf + LWS_PRE, len, LWS_WRITE_TEXT); lws_write (wsi, out_buf + LWS_PRE, len, LWS_WRITE_TEXT);
} else { } else {
PBD::error << "ArdourWebsockets: cannot serialize message" << endmsg; PBD::error << "ArdourWebsockets: cannot serialize message" << endmsg;
} }
if (!pending.empty ()) { if (!pending.empty ()) {
lws_callback_on_writable (wsi); lws_callback_on_writable (wsi);
} }
} }
bool bool
WebsocketsServer::io_handler (Glib::IOCondition ioc, lws_sockfd_type fd) WebsocketsServer::io_handler (Glib::IOCondition ioc, lws_sockfd_type fd)
{ {
// IO_IN=1, IO_PRI=2, IO_ERR=8, IO_HUP=16 /* IO_IN=1, IO_PRI=2, IO_ERR=8, IO_HUP=16 */
//printf ("io_handler ioc = %d\n", ioc); //printf ("io_handler ioc = %d\n", ioc);
LwsPollFdGlibSourceMap::iterator it = _fd_ctx.find (fd); LwsPollFdGlibSourceMap::iterator it = _fd_ctx.find (fd);
if (it == _fd_ctx.end ()) { if (it == _fd_ctx.end ()) {
return false; return false;
} }
struct lws_pollfd *lws_pfd = &it->second.lws_pfd; struct lws_pollfd* lws_pfd = &it->second.lws_pfd;
lws_pfd->revents = ioc_to_events (ioc); lws_pfd->revents = ioc_to_events (ioc);
if (lws_service_fd (_lws_context, lws_pfd) < 0) { if (lws_service_fd (_lws_context, lws_pfd) < 0) {
return false; return false;
} }
return ioc & (Glib::IO_IN | Glib::IO_OUT); return ioc & (Glib::IO_IN | Glib::IO_OUT);
} }
IOCondition IOCondition
WebsocketsServer::events_to_ioc (int events) WebsocketsServer::events_to_ioc (int events)
{ {
IOCondition ioc; IOCondition ioc;
if (events & LWS_POLLIN) { if (events & LWS_POLLIN) {
ioc = Glib::IO_IN; ioc = Glib::IO_IN;
} else if (events & LWS_POLLOUT) { } else if (events & LWS_POLLOUT) {
ioc = Glib::IO_OUT; ioc = Glib::IO_OUT;
} else if (events & LWS_POLLHUP) { } else if (events & LWS_POLLHUP) {
ioc = Glib::IO_HUP; ioc = Glib::IO_HUP;
} }
return ioc; return ioc;
}
int
WebsocketsServer::ioc_to_events (IOCondition ioc)
{
int events = 0;
if (ioc & Glib::IO_IN) {
events |= LWS_POLLIN;
}
if (ioc & Glib::IO_OUT) {
events |= LWS_POLLOUT;
}
if (ioc & (Glib::IO_HUP | Glib::IO_ERR)) {
events |= LWS_POLLHUP;
}
return events;
} }
int int
WebsocketsServer::lws_callback(struct lws* wsi, enum lws_callback_reasons reason, WebsocketsServer::ioc_to_events (IOCondition ioc)
void *user, void *in, size_t len)
{ {
void *ctx_userdata = lws_context_user (lws_get_context (wsi)); int events = 0;
WebsocketsServer *server = static_cast<WebsocketsServer *>(ctx_userdata);
switch (reason) { if (ioc & Glib::IO_IN) {
case LWS_CALLBACK_ADD_POLL_FD: events |= LWS_POLLIN;
server->add_poll_fd (static_cast<struct lws_pollargs *>(in)); }
break;
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
server->mod_poll_fd (static_cast<struct lws_pollargs *>(in));
break;
case LWS_CALLBACK_DEL_POLL_FD: if (ioc & Glib::IO_OUT) {
server->del_poll_fd (static_cast<struct lws_pollargs *>(in)); events |= LWS_POLLOUT;
break; }
case LWS_CALLBACK_ESTABLISHED: if (ioc & (Glib::IO_HUP | Glib::IO_ERR)) {
server->add_client (wsi); events |= LWS_POLLHUP;
break; }
case LWS_CALLBACK_CLOSED: return events;
server->del_client (wsi); }
break;
int
case LWS_CALLBACK_RECEIVE: WebsocketsServer::lws_callback (struct lws* wsi, enum lws_callback_reasons reason,
server->recv_client (wsi, in, len); void* user, void* in, size_t len)
break; {
void* ctx_userdata = lws_context_user (lws_get_context (wsi));
case LWS_CALLBACK_SERVER_WRITEABLE: WebsocketsServer* server = static_cast<WebsocketsServer*> (ctx_userdata);
server->write_client (wsi);
break; switch (reason) {
case LWS_CALLBACK_ADD_POLL_FD:
default: server->add_poll_fd (static_cast<struct lws_pollargs*> (in));
break; break;
}
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
return 0; server->mod_poll_fd (static_cast<struct lws_pollargs*> (in));
break;
case LWS_CALLBACK_DEL_POLL_FD:
server->del_poll_fd (static_cast<struct lws_pollargs*> (in));
break;
case LWS_CALLBACK_ESTABLISHED:
server->add_client (wsi);
break;
case LWS_CALLBACK_CLOSED:
server->del_client (wsi);
break;
case LWS_CALLBACK_RECEIVE:
server->recv_client (wsi, in, len);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
server->write_client (wsi);
break;
default:
break;
}
return 0;
} }

View file

@ -19,9 +19,9 @@
#ifndef websockets_server_h #ifndef websockets_server_h
#define websockets_server_h #define websockets_server_h
#include <boost/unordered_map.hpp>
#include <glibmm.h> #include <glibmm.h>
#include <libwebsockets.h> #include <libwebsockets.h>
#include <boost/unordered_map.hpp>
#if LWS_LIBRARY_VERSION_MAJOR < 3 #if LWS_LIBRARY_VERSION_MAJOR < 3
// <libwebsockets.h> includes <uv.h> which in turn includes // <libwebsockets.h> includes <uv.h> which in turn includes
@ -34,63 +34,60 @@
// version 3 in order to keep things simpler for the end user // version 3 in order to keep things simpler for the end user
#endif #endif
#include "component.h"
#include "client.h" #include "client.h"
#include "state.h" #include "component.h"
#include "message.h" #include "message.h"
#include "state.h"
#define WEBSOCKET_LISTEN_PORT 9000 #define WEBSOCKET_LISTEN_PORT 9000
struct LwsPollFdGlibSource { struct LwsPollFdGlibSource {
struct lws_pollfd lws_pfd; struct lws_pollfd lws_pfd;
Glib::RefPtr<Glib::IOChannel> g_channel; Glib::RefPtr<Glib::IOChannel> g_channel;
Glib::RefPtr<Glib::IOSource> rg_iosrc; Glib::RefPtr<Glib::IOSource> rg_iosrc;
Glib::RefPtr<Glib::IOSource> wg_iosrc; Glib::RefPtr<Glib::IOSource> wg_iosrc;
}; };
class WebsocketsServer : public SurfaceComponent class WebsocketsServer : public SurfaceComponent
{ {
public: public:
WebsocketsServer (ArdourSurface::ArdourWebsockets&);
virtual ~WebsocketsServer (){};
WebsocketsServer (ArdourSurface::ArdourWebsockets&); int start ();
virtual ~WebsocketsServer () {}; int stop ();
int start (); void update_client (Client, const NodeState&, bool);
int stop (); void update_all_clients (const NodeState&, bool);
void update_client (Client, const NodeState&, bool); private:
void update_all_clients (const NodeState&, bool); struct lws_protocols _lws_proto[2];
struct lws_context_creation_info _lws_info;
struct lws_context* _lws_context;
private: Glib::RefPtr<Glib::IOChannel> _channel;
struct lws_protocols _lws_proto[2]; typedef boost::unordered_map<lws_sockfd_type, LwsPollFdGlibSource> LwsPollFdGlibSourceMap;
struct lws_context_creation_info _lws_info; LwsPollFdGlibSourceMap _fd_ctx;
struct lws_context *_lws_context;
Glib::RefPtr<Glib::IOChannel> _channel; typedef boost::unordered_map<Client, ClientContext> ClientContextMap;
ClientContextMap _client_ctx;
typedef boost::unordered_map<lws_sockfd_type, LwsPollFdGlibSource> LwsPollFdGlibSourceMap; void add_poll_fd (struct lws_pollargs*);
LwsPollFdGlibSourceMap _fd_ctx; void mod_poll_fd (struct lws_pollargs*);
void del_poll_fd (struct lws_pollargs*);
typedef boost::unordered_map<Client, ClientContext> ClientContextMap; void add_client (Client);
ClientContextMap _client_ctx; void del_client (Client);
void recv_client (Client, void* buf, size_t len);
void write_client (Client);
void add_poll_fd (struct lws_pollargs*); bool io_handler (Glib::IOCondition, lws_sockfd_type);
void mod_poll_fd (struct lws_pollargs*);
void del_poll_fd (struct lws_pollargs*);
void add_client (Client);
void del_client (Client);
void recv_client (Client, void *buf, size_t len);
void write_client (Client);
bool io_handler (Glib::IOCondition, lws_sockfd_type); Glib::IOCondition events_to_ioc (int);
int ioc_to_events (Glib::IOCondition);
Glib::IOCondition events_to_ioc (int);
int ioc_to_events (Glib::IOCondition);
static int lws_callback(struct lws*, enum lws_callback_reasons, void *, void *, size_t);
static int lws_callback (struct lws*, enum lws_callback_reasons, void*, void*, size_t);
}; };
#endif // websockets_server_h #endif // websockets_server_h

View file

@ -16,98 +16,105 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <sstream>
#include <boost/unordered_set.hpp> #include <boost/unordered_set.hpp>
#include <sstream>
#include "state.h" #include "state.h"
NodeState::NodeState () { } NodeState::NodeState () {}
NodeState::NodeState (std::string node) NodeState::NodeState (std::string node)
: _node (node) { } : _node (node)
{
}
NodeState::NodeState (std::string node, AddressVector addr, ValueVector val) NodeState::NodeState (std::string node, AddressVector addr, ValueVector val)
: _node (node) : _node (node)
, _addr (addr) , _addr (addr)
, _val (val) { } , _val (val)
{
}
std::string std::string
NodeState::debug_str () const NodeState::debug_str () const
{ {
std::stringstream s; std::stringstream s;
s << "node = " << _node; s << "node = " << _node;
if (!_addr.empty ()) { if (!_addr.empty ()) {
s << std::endl << " addr = "; s << std::endl
<< " addr = ";
for (AddressVector::const_iterator it = _addr.begin (); it != _addr.end (); ++it) { for (AddressVector::const_iterator it = _addr.begin (); it != _addr.end (); ++it) {
s << *it << ";"; s << *it << ";";
} }
} }
for (ValueVector::const_iterator it = _val.begin (); it != _val.end (); ++it) { for (ValueVector::const_iterator it = _val.begin (); it != _val.end (); ++it) {
s << std::endl << " val " << it->debug_str (); s << std::endl
} << " val " << it->debug_str ();
}
return s.str ();
return s.str ();
} }
int int
NodeState::n_addr () const NodeState::n_addr () const
{ {
return static_cast<int>(_addr.size ()); return static_cast<int> (_addr.size ());
} }
uint32_t uint32_t
NodeState::nth_addr (int n) const NodeState::nth_addr (int n) const
{ {
return _addr[n]; return _addr[n];
} }
void void
NodeState::add_addr (uint32_t addr) NodeState::add_addr (uint32_t addr)
{ {
_addr.push_back (addr); _addr.push_back (addr);
} }
int int
NodeState::n_val () const NodeState::n_val () const
{ {
return static_cast<int>(_val.size ()); return static_cast<int> (_val.size ());
} }
TypedValue TypedValue
NodeState::nth_val (int n) const NodeState::nth_val (int n) const
{ {
if (n_val () < n) { if (n_val () < n) {
return TypedValue (); return TypedValue ();
} }
return _val[n]; return _val[n];
} }
void void
NodeState::add_val (TypedValue val) NodeState::add_val (TypedValue val)
{ {
_val.push_back (val); _val.push_back (val);
} }
std::size_t std::size_t
NodeState::node_addr_hash () const NodeState::node_addr_hash () const
{ {
std::size_t seed = 0; std::size_t seed = 0;
boost::hash_combine (seed, _node); boost::hash_combine (seed, _node);
boost::hash_combine (seed, _addr); boost::hash_combine (seed, _addr);
return seed; return seed;
} }
bool bool
NodeState::operator== (const NodeState& other) const NodeState::operator== (const NodeState& other) const
{ {
return node_addr_hash () == other.node_addr_hash (); return node_addr_hash () == other.node_addr_hash ();
} }
std::size_t hash_value (const NodeState &state) std::size_t
hash_value (const NodeState& state)
{ {
return state.node_addr_hash (); return state.node_addr_hash ();
} }

View file

@ -19,64 +19,66 @@
#ifndef node_state_h #ifndef node_state_h
#define node_state_h #define node_state_h
#include <stdint.h>
#include <climits> #include <climits>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <stdint.h>
#include <vector> #include <vector>
#include "typed_value.h" #include "typed_value.h"
#define ADDR_NONE UINT_MAX #define ADDR_NONE UINT_MAX
namespace Node { namespace Node
const std::string tempo = "tempo"; {
const std::string strip_desc = "strip_desc"; const std::string tempo = "tempo";
const std::string strip_meter = "strip_meter"; const std::string strip_desc = "strip_desc";
const std::string strip_gain = "strip_gain"; const std::string strip_meter = "strip_meter";
const std::string strip_pan = "strip_pan"; const std::string strip_gain = "strip_gain";
const std::string strip_mute = "strip_mute"; const std::string strip_pan = "strip_pan";
const std::string strip_plugin_desc = "strip_plugin_desc"; const std::string strip_mute = "strip_mute";
const std::string strip_plugin_enable = "strip_plugin_enable"; const std::string strip_plugin_desc = "strip_plugin_desc";
const std::string strip_plugin_param_desc = "strip_plugin_param_desc"; const std::string strip_plugin_enable = "strip_plugin_enable";
const std::string strip_plugin_param_value = "strip_plugin_param_value"; const std::string strip_plugin_param_desc = "strip_plugin_param_desc";
} const std::string strip_plugin_param_value = "strip_plugin_param_value";
} // namespace Node
typedef std::vector<uint32_t> AddressVector; typedef std::vector<uint32_t> AddressVector;
typedef std::vector<TypedValue> ValueVector; typedef std::vector<TypedValue> ValueVector;
class NodeState { class NodeState
{
public:
NodeState ();
NodeState (std::string);
NodeState (std::string, AddressVector, ValueVector = ValueVector ());
public: std::string debug_str () const;
NodeState (); std::string node () const
NodeState (std::string); {
NodeState (std::string, AddressVector, ValueVector = ValueVector()); return _node;
}
std::string debug_str () const; int n_addr () const;
uint32_t nth_addr (int) const;
void add_addr (uint32_t);
std::string node () const { return _node; } int n_val () const;
TypedValue nth_val (int) const;
void add_val (TypedValue);
int n_addr () const; std::size_t node_addr_hash () const;
uint32_t nth_addr (int) const;
void add_addr (uint32_t);
int n_val () const; bool operator== (const NodeState& other) const;
TypedValue nth_val (int) const;
void add_val (TypedValue);
std::size_t node_addr_hash () const;
bool operator== (const NodeState& other) const;
private:
std::string _node;
AddressVector _addr;
ValueVector _val;
private:
std::string _node;
AddressVector _addr;
ValueVector _val;
}; };
std::size_t hash_value (const NodeState&); std::size_t
hash_value (const NodeState&);
#endif // node_state_h #endif // node_state_h

View file

@ -16,9 +16,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "ardour/session.h"
#include "ardour/plugin_insert.h"
#include "ardour/dB.h" #include "ardour/dB.h"
#include "ardour/plugin_insert.h"
#include "ardour/session.h"
#include "pbd/controllable.h" #include "pbd/controllable.h"
#include "strips.h" #include "strips.h"
@ -28,65 +28,65 @@ using namespace ARDOUR;
int int
ArdourStrips::start () ArdourStrips::start ()
{ {
// take an indexed snapshot of current strips /* take an indexed snapshot of current strips */
StripableList strips; StripableList strips;
session ().get_stripables (strips, PresentationInfo::AllStripables); session ().get_stripables (strips, PresentationInfo::AllStripables);
for (StripableList::iterator strip = strips.begin (); strip != strips.end (); ++strip) { for (StripableList::iterator strip = strips.begin (); strip != strips.end (); ++strip) {
_strips.push_back (*strip); _strips.push_back (*strip);
} }
return 0; return 0;
} }
int int
ArdourStrips::stop () ArdourStrips::stop ()
{ {
_strips.clear (); _strips.clear ();
return 0; return 0;
} }
double double
ArdourStrips::to_db (double k) ArdourStrips::to_db (double k)
{ {
if (k == 0) { if (k == 0) {
return -std::numeric_limits<double>::infinity (); return -std::numeric_limits<double>::infinity ();
} }
float db = accurate_coefficient_to_dB (static_cast<float>(k)); float db = accurate_coefficient_to_dB (static_cast<float> (k));
return static_cast<double>(db); return static_cast<double> (db);
} }
double double
ArdourStrips::from_db (double db) ArdourStrips::from_db (double db)
{ {
if (db < -192) { if (db < -192) {
return 0; return 0;
} }
float k = dB_to_coefficient (static_cast<float>(db));
return static_cast<double>(k); float k = dB_to_coefficient (static_cast<float> (db));
return static_cast<double> (k);
} }
double double
ArdourStrips::strip_gain (uint32_t strip_n) const ArdourStrips::strip_gain (uint32_t strip_n) const
{ {
return to_db (nth_strip (strip_n)->gain_control ()->get_value ()); return to_db (nth_strip (strip_n)->gain_control ()->get_value ());
} }
void void
ArdourStrips::set_strip_gain (uint32_t strip_n, double db) ArdourStrips::set_strip_gain (uint32_t strip_n, double db)
{ {
nth_strip (strip_n)->gain_control ()->set_value (from_db (db), PBD::Controllable::NoGroup); nth_strip (strip_n)->gain_control ()->set_value (from_db (db), PBD::Controllable::NoGroup);
} }
double double
ArdourStrips::strip_pan (uint32_t strip_n) const ArdourStrips::strip_pan (uint32_t strip_n) const
{ {
// scale from [0.0 ; 1.0] to [-1.0 ; 1.0] /* scale from [0.0 ; 1.0] to [-1.0 ; 1.0] */
return 2.0 * nth_strip (strip_n)->pan_azimuth_control ()->get_value () - 1.0; return 2.0 * nth_strip (strip_n)->pan_azimuth_control ()->get_value () - 1.0;
} }
void void
@ -103,129 +103,129 @@ ArdourStrips::set_strip_pan (uint32_t strip_n, double value)
bool bool
ArdourStrips::strip_mute (uint32_t strip_n) const ArdourStrips::strip_mute (uint32_t strip_n) const
{ {
return nth_strip (strip_n)->mute_control ()->muted (); return nth_strip (strip_n)->mute_control ()->muted ();
} }
void void
ArdourStrips::set_strip_mute (uint32_t strip_n, bool mute) ArdourStrips::set_strip_mute (uint32_t strip_n, bool mute)
{ {
nth_strip (strip_n)->mute_control ()->set_value (mute ? 1.0 : 0.0, PBD::Controllable::NoGroup); nth_strip (strip_n)->mute_control ()->set_value (mute ? 1.0 : 0.0, PBD::Controllable::NoGroup);
} }
bool bool
ArdourStrips::strip_plugin_enabled (uint32_t strip_n, uint32_t plugin_n) const ArdourStrips::strip_plugin_enabled (uint32_t strip_n, uint32_t plugin_n) const
{ {
return strip_plugin_insert (strip_n, plugin_n)->enabled (); return strip_plugin_insert (strip_n, plugin_n)->enabled ();
} }
void void
ArdourStrips::set_strip_plugin_enabled (uint32_t strip_n, uint32_t plugin_n, bool enabled) ArdourStrips::set_strip_plugin_enabled (uint32_t strip_n, uint32_t plugin_n, bool enabled)
{ {
strip_plugin_insert (strip_n, plugin_n)->enable (enabled); strip_plugin_insert (strip_n, plugin_n)->enable (enabled);
} }
TypedValue TypedValue
ArdourStrips::strip_plugin_param_value (uint32_t strip_n, uint32_t plugin_n, ArdourStrips::strip_plugin_param_value (uint32_t strip_n, uint32_t plugin_n,
uint32_t param_n) const uint32_t param_n) const
{ {
return plugin_param_value (strip_plugin_param_control (strip_n, plugin_n, param_n)); return plugin_param_value (strip_plugin_param_control (strip_n, plugin_n, param_n));
} }
void void
ArdourStrips::set_strip_plugin_param_value (uint32_t strip_n, uint32_t plugin_n, ArdourStrips::set_strip_plugin_param_value (uint32_t strip_n, uint32_t plugin_n,
uint32_t param_n, TypedValue value) uint32_t param_n, TypedValue value)
{ {
boost::shared_ptr<AutomationControl> control = strip_plugin_param_control ( boost::shared_ptr<AutomationControl> control = strip_plugin_param_control (
strip_n, plugin_n, param_n); strip_n, plugin_n, param_n);
if (control) { if (control) {
ParameterDescriptor pd = control->desc (); ParameterDescriptor pd = control->desc ();
double dbl_val; double dbl_val;
if (pd.toggled) { if (pd.toggled) {
dbl_val = static_cast<double>(static_cast<bool>(value)); dbl_val = static_cast<double> (static_cast<bool> (value));
} else if (pd.enumeration || pd.integer_step) { } else if (pd.enumeration || pd.integer_step) {
dbl_val = static_cast<double>(static_cast<int>(value)); dbl_val = static_cast<double> (static_cast<int> (value));
} else { } else {
dbl_val = static_cast<double>(value); dbl_val = static_cast<double> (value);
} }
control->set_value (dbl_val, PBD::Controllable::NoGroup); control->set_value (dbl_val, PBD::Controllable::NoGroup);
} }
} }
uint32_t uint32_t
ArdourStrips::strip_count () const ArdourStrips::strip_count () const
{ {
return _strips.size (); return _strips.size ();
} }
boost::shared_ptr<Stripable> boost::shared_ptr<Stripable>
ArdourStrips::nth_strip (uint32_t strip_n) const ArdourStrips::nth_strip (uint32_t strip_n) const
{ {
if (strip_n < _strips.size ()) { if (strip_n < _strips.size ()) {
return _strips[strip_n]; return _strips[strip_n];
} }
return boost::shared_ptr<Stripable>(); return boost::shared_ptr<Stripable> ();
} }
TypedValue TypedValue
ArdourStrips::plugin_param_value (boost::shared_ptr<ARDOUR::AutomationControl> control) ArdourStrips::plugin_param_value (boost::shared_ptr<ARDOUR::AutomationControl> control)
{ {
TypedValue value = TypedValue (); TypedValue value = TypedValue ();
if (control) { if (control) {
ParameterDescriptor pd = control->desc (); 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 ());
}
}
return 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;
} }
boost::shared_ptr<PluginInsert> boost::shared_ptr<PluginInsert>
ArdourStrips::strip_plugin_insert (uint32_t strip_n, uint32_t plugin_n) const ArdourStrips::strip_plugin_insert (uint32_t strip_n, uint32_t plugin_n) const
{ {
boost::shared_ptr<Stripable> strip = nth_strip (strip_n); boost::shared_ptr<Stripable> strip = nth_strip (strip_n);
boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (strip); boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (strip);
boost::shared_ptr<Processor> processor = route->nth_plugin (plugin_n); boost::shared_ptr<Processor> processor = route->nth_plugin (plugin_n);
if (processor) { if (processor) {
boost::shared_ptr<PluginInsert> insert = boost::shared_ptr<PluginInsert> insert =
boost::static_pointer_cast<PluginInsert> (processor); boost::static_pointer_cast<PluginInsert> (processor);
if (insert) {
return insert;
}
}
return boost::shared_ptr<PluginInsert>(); if (insert) {
return insert;
}
}
return boost::shared_ptr<PluginInsert> ();
} }
boost::shared_ptr<AutomationControl> boost::shared_ptr<AutomationControl>
ArdourStrips::strip_plugin_param_control (uint32_t strip_n, uint32_t plugin_n, ArdourStrips::strip_plugin_param_control (uint32_t strip_n, uint32_t plugin_n,
uint32_t param_n) const uint32_t param_n) const
{ {
boost::shared_ptr<PluginInsert> insert = strip_plugin_insert (strip_n, plugin_n); boost::shared_ptr<PluginInsert> insert = strip_plugin_insert (strip_n, plugin_n);
if (insert) { if (insert) {
bool ok = false; bool ok = false;
boost::shared_ptr<Plugin> plugin = insert->plugin (); boost::shared_ptr<Plugin> plugin = insert->plugin ();
uint32_t control_id = plugin->nth_parameter (param_n, ok); uint32_t control_id = plugin->nth_parameter (param_n, ok);
if (ok && plugin->parameter_is_input (control_id)) { if (ok && plugin->parameter_is_input (control_id)) {
boost::shared_ptr<AutomationControl> control = boost::shared_ptr<AutomationControl> control =
insert->automation_control (Evoral::Parameter(PluginAutomation, 0, control_id)); insert->automation_control (Evoral::Parameter (PluginAutomation, 0, control_id));
return control; return control;
} }
} }
return boost::shared_ptr<AutomationControl>(); return boost::shared_ptr<AutomationControl> ();
} }

View file

@ -24,47 +24,45 @@
class ArdourStrips : public SurfaceComponent class ArdourStrips : public SurfaceComponent
{ {
public: public:
ArdourStrips (ArdourSurface::ArdourWebsockets& surface)
: SurfaceComponent (surface){};
virtual ~ArdourStrips (){};
ArdourStrips (ArdourSurface::ArdourWebsockets& surface) : SurfaceComponent (surface) {}; int start ();
virtual ~ArdourStrips () {}; int stop ();
int start (); static double to_db (double);
int stop (); static double from_db (double);
static double to_db (double); double strip_gain (uint32_t) const;
static double from_db (double); void set_strip_gain (uint32_t, double);
double strip_gain (uint32_t) const; double strip_pan (uint32_t) const;
void set_strip_gain (uint32_t, double); void set_strip_pan (uint32_t, double);
double strip_pan (uint32_t) const; bool strip_mute (uint32_t) const;
void set_strip_pan (uint32_t, double); void set_strip_mute (uint32_t, bool);
bool strip_mute (uint32_t) const; bool strip_plugin_enabled (uint32_t, uint32_t) const;
void set_strip_mute (uint32_t, bool); void set_strip_plugin_enabled (uint32_t, uint32_t, bool);
bool strip_plugin_enabled (uint32_t, uint32_t) const;
void set_strip_plugin_enabled (uint32_t, uint32_t, bool);
TypedValue strip_plugin_param_value (uint32_t, uint32_t, uint32_t) const; TypedValue strip_plugin_param_value (uint32_t, uint32_t, uint32_t) const;
void set_strip_plugin_param_value (uint32_t, uint32_t, uint32_t, TypedValue); void set_strip_plugin_param_value (uint32_t, uint32_t, uint32_t, TypedValue);
uint32_t strip_count () const; uint32_t strip_count () const;
boost::shared_ptr<ARDOUR::Stripable> nth_strip (uint32_t) const; boost::shared_ptr<ARDOUR::Stripable> nth_strip (uint32_t) const;
boost::shared_ptr<ARDOUR::PluginInsert> strip_plugin_insert (uint32_t, uint32_t) const; boost::shared_ptr<ARDOUR::PluginInsert> strip_plugin_insert (uint32_t, uint32_t) const;
boost::shared_ptr<ARDOUR::AutomationControl> strip_plugin_param_control(
uint32_t, uint32_t, uint32_t) const;
static TypedValue plugin_param_value (boost::shared_ptr<ARDOUR::AutomationControl>); boost::shared_ptr<ARDOUR::AutomationControl> strip_plugin_param_control (
uint32_t, uint32_t, uint32_t) const;
private: static TypedValue plugin_param_value (boost::shared_ptr<ARDOUR::AutomationControl>);
typedef std::vector<boost::shared_ptr<ARDOUR::Stripable> > StripableVector;
StripableVector _strips;
private:
typedef std::vector<boost::shared_ptr<ARDOUR::Stripable> > StripableVector;
StripableVector _strips;
}; };
#endif // ardour_strips_h #endif // ardour_strips_h

View file

@ -16,10 +16,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <boost/lexical_cast.hpp>
#include <cmath> #include <cmath>
#include <limits> #include <limits>
#include <string> #include <string>
#include <boost/lexical_cast.hpp>
#include "typed_value.h" #include "typed_value.h"
@ -29,156 +29,161 @@ TypedValue::TypedValue ()
: _type (Empty) : _type (Empty)
, _b (false) , _b (false)
, _i (0) , _i (0)
, _d (0) { } , _d (0)
{
}
TypedValue::TypedValue (bool value) TypedValue::TypedValue (bool value)
: _type (Bool) : _type (Bool)
, _b (value) , _b (value)
, _i (0) , _i (0)
, _d (0) { } , _d (0)
{
}
TypedValue::TypedValue (int value) TypedValue::TypedValue (int value)
: _type (Int) : _type (Int)
, _b (false) , _b (false)
, _i (value) , _i (value)
, _d (0) { } , _d (0)
{
}
TypedValue::TypedValue (double value) TypedValue::TypedValue (double value)
: _type (Double) : _type (Double)
, _b (false) , _b (false)
, _i (0) , _i (0)
, _d (value) { } , _d (value)
{
}
TypedValue::TypedValue (std::string value) TypedValue::TypedValue (std::string value)
: _type (String) : _type (String)
, _b (false) , _b (false)
, _i (0) , _i (0)
, _d (0) , _d (0)
, _s (value) { } , _s (value)
TypedValue::operator
bool () const
{ {
switch (_type) {
case Bool:
return _b;
case Int:
return _i != 0;
case Double:
return _d != 0;
case String:
return _s == "true";
default:
return false;
}
} }
TypedValue::operator TypedValue::operator bool () const
int () const
{ {
switch (_type) { switch (_type) {
case Int: case Bool:
return _i; return _b;
case Bool: case Int:
return _b ? 1 : 0; return _i != 0;
case Double: case Double:
return static_cast<int>(_d); return _d != 0;
case String: case String:
try { return _s == "true";
return boost::lexical_cast<int> (_s); default:
} catch (const boost::bad_lexical_cast&) { return false;
return 0; }
}
default:
return 0;
}
} }
TypedValue::operator TypedValue::operator int () const
double () const
{ {
switch (_type) { switch (_type) {
case Double: case Int:
return _d; return _i;
case Bool: case Bool:
return _b ? 1.f : 0; return _b ? 1 : 0;
case Int: case Double:
return static_cast<double>(_i); return static_cast<int> (_d);
case String: case String:
try { try {
return boost::lexical_cast<double> (_s); return boost::lexical_cast<int> (_s);
} catch (const boost::bad_lexical_cast&) { } catch (const boost::bad_lexical_cast&) {
return 0; return 0;
} }
default: default:
return 0; return 0;
} }
} }
TypedValue::operator TypedValue::operator double () const
std::string () const
{ {
switch (_type) { switch (_type) {
case String: case Double:
return _s; return _d;
case Bool: case Bool:
return _b ? "true" : "false"; return _b ? 1.f : 0;
case Int: case Int:
return boost::lexical_cast<std::string> (_i); return static_cast<double> (_i);
case Double: case String:
return boost::lexical_cast<std::string> (_d); try {
default: return boost::lexical_cast<double> (_s);
return ""; } catch (const boost::bad_lexical_cast&) {
} return 0;
}
default:
return 0;
}
} }
TypedValue::operator std::string () const
{
switch (_type) {
case String:
return _s;
case Bool:
return _b ? "true" : "false";
case Int:
return boost::lexical_cast<std::string> (_i);
case Double:
return boost::lexical_cast<std::string> (_d);
default:
return "";
}
}
bool bool
TypedValue::operator== (const TypedValue& other) const TypedValue::operator== (const TypedValue& other) const
{ {
if (_type != other._type) { if (_type != other._type) {
// make an exception when comparing doubles and ints /* make an exception when comparing doubles and ints
// for example browser json implementations will send * for example browser json implementations will send
// 1 instead of 1.0 removing any type hint * 1 instead of 1.0 removing any type hint
if ((_type == Int) && (other._type == Double)) { */
return fabs (static_cast<double>(_i) - other._d) < DBL_TOLERANCE; if ((_type == Int) && (other._type == Double)) {
} else if ((_type == Double) && (other._type == Int)) { return fabs (static_cast<double> (_i) - other._d) < DBL_TOLERANCE;
return fabs (_d - static_cast<double>(other._i)) < DBL_TOLERANCE; } else if ((_type == Double) && (other._type == Int)) {
} return fabs (_d - static_cast<double> (other._i)) < DBL_TOLERANCE;
}
return false; return false;
} }
switch (_type) { switch (_type) {
case Bool: case Bool:
return _b == other._b; return _b == other._b;
case Int: case Int:
return _i == other._i; return _i == other._i;
case Double: { case Double: {
double inf = std::numeric_limits<double>::infinity (); double inf = std::numeric_limits<double>::infinity ();
return ((_d == inf) && (other._d == inf)) return ((_d == inf) && (other._d == inf)) || ((_d == -inf) && (other._d == -inf)) || (fabs (_d - other._d) < DBL_TOLERANCE);
|| ((_d == -inf) && (other._d == -inf)) }
|| (fabs (_d - other._d) < DBL_TOLERANCE); case String:
} return _s == other._s;
case String: default:
return _s == other._s; return false;
default: }
return false;
}
} }
bool bool
TypedValue::operator!= (const TypedValue& other) const TypedValue::operator!= (const TypedValue& other) const
{ {
return !(*this == other); return !(*this == other);
} }
std::string std::string
TypedValue::debug_str () const TypedValue::debug_str () const
{ {
char s[256]; char s[256];
sprintf(s, "type = %d; b = %d; i = %d; d = %f; s = \"%s\"", sprintf (s, "type = %d; b = %d; i = %d; d = %f; s = \"%s\"",
_type, _b, _i, _d, _s.c_str ()); _type, _b, _i, _d, _s.c_str ());
return s; return s;
} }

View file

@ -23,43 +23,46 @@
class TypedValue class TypedValue
{ {
public: public:
enum Type {
Empty,
Bool,
Int,
Double,
String
};
enum Type { TypedValue ();
Empty, TypedValue (bool);
Bool, TypedValue (int);
Int, TypedValue (double);
Double, TypedValue (std::string);
String
};
TypedValue (); bool empty () const
TypedValue (bool); {
TypedValue (int); return _type == Empty;
TypedValue (double); };
TypedValue (std::string); Type type () const
{
return _type;
};
bool empty () const { return _type == Empty; }; operator bool () const;
Type type () const { return _type; }; operator int () const;
operator double () const;
operator std::string () const;
operator bool () const; bool operator== (const TypedValue& other) const;
operator int () const; bool operator!= (const TypedValue& other) const;
operator double () const;
operator std::string () const;
bool operator== (const TypedValue& other) const; std::string debug_str () const;
bool operator!= (const TypedValue& other) const;
std::string debug_str () const;
private:
Type _type;
bool _b;
int _i;
double _d;
std::string _s;
private:
Type _type;
bool _b;
int _i;
double _d;
std::string _s;
}; };
#endif // typed_value_h #endif // typed_value_h