mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 08:36:32 +01:00
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:
parent
224be91211
commit
5e3480ba8f
23 changed files with 1260 additions and 1217 deletions
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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> ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue