summaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2013-02-02 02:16:23 +0000
committerDavid Robillard <d@drobilla.net>2013-02-02 02:16:23 +0000
commitd049b582e1db60ee0f6fd02a40202145488c7288 (patch)
tree4b30ba2522a14863ce76f672f537dcca0c14c34e /src/server
parent73a01c1bd8d6cf92522a433cd2b0bd491f2af99a (diff)
downloadingen-d049b582e1db60ee0f6fd02a40202145488c7288.tar.gz
ingen-d049b582e1db60ee0f6fd02a40202145488c7288.tar.bz2
ingen-d049b582e1db60ee0f6fd02a40202145488c7288.zip
Add option to enable/disable canvas animation (fix/avoid #879).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5016 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/server')
-rw-r--r--src/server/Broadcaster.cpp18
-rw-r--r--src/server/Broadcaster.hpp21
-rw-r--r--src/server/Context.cpp6
-rw-r--r--src/server/Context.hpp8
-rw-r--r--src/server/DuplexPort.cpp5
-rw-r--r--src/server/InputPort.cpp12
-rw-r--r--src/server/OutputPort.cpp5
-rw-r--r--src/server/PortImpl.cpp37
-rw-r--r--src/server/PortImpl.hpp18
-rw-r--r--src/server/events/Delta.cpp12
-rw-r--r--src/server/internals/Controller.cpp2
-rw-r--r--src/server/internals/Trigger.cpp2
12 files changed, 105 insertions, 41 deletions
diff --git a/src/server/Broadcaster.cpp b/src/server/Broadcaster.cpp
index f3bc96f7..8e53164f 100644
--- a/src/server/Broadcaster.cpp
+++ b/src/server/Broadcaster.cpp
@@ -26,10 +26,16 @@
namespace Ingen {
namespace Server {
+Broadcaster::Broadcaster()
+ : _must_broadcast(false)
+ , _bundle_depth(0)
+{}
+
Broadcaster::~Broadcaster()
{
Glib::Mutex::Lock lock(_clients_mutex);
_clients.clear();
+ _broadcastees.clear();
}
/** Register a client to receive messages over the notification band.
@@ -51,9 +57,21 @@ Broadcaster::unregister_client(const Raul::URI& uri)
{
Glib::Mutex::Lock lock(_clients_mutex);
const size_t erased = _clients.erase(uri);
+ _broadcastees.erase(uri);
return (erased > 0);
}
+void
+Broadcaster::set_broadcast(const Raul::URI& client, bool broadcast)
+{
+ if (broadcast) {
+ _broadcastees.insert(client);
+ } else {
+ _broadcastees.erase(client);
+ }
+ _must_broadcast.store(!_broadcastees.empty());
+}
+
/** Looks up the client with the given source @a uri (which is used as the
* unique identifier for registered clients).
*/
diff --git a/src/server/Broadcaster.hpp b/src/server/Broadcaster.hpp
index 3162742b..5de5ec8f 100644
--- a/src/server/Broadcaster.hpp
+++ b/src/server/Broadcaster.hpp
@@ -17,8 +17,10 @@
#ifndef INGEN_ENGINE_CLIENTBROADCASTER_HPP
#define INGEN_ENGINE_CLIENTBROADCASTER_HPP
+#include <atomic>
#include <list>
#include <map>
+#include <set>
#include <string>
#include <glibmm/thread.h>
@@ -41,12 +43,21 @@ namespace Server {
class Broadcaster : public Interface
{
public:
- Broadcaster() : _bundle_depth(0) {}
+ Broadcaster();
~Broadcaster();
void register_client(const Raul::URI& uri, SPtr<Interface> client);
bool unregister_client(const Raul::URI& uri);
+ void set_broadcast(const Raul::URI& client, bool broadcast);
+
+ /** Return true iff there are any clients with broadcasting enabled.
+ *
+ * This is used in the audio thread to decide whether or not notifications
+ * should be calculated and emitted.
+ */
+ bool must_broadcast() const { return _must_broadcast; }
+
/** A handle that represents a transfer of possibly several changes.
*
* This object going out of scope signifies the transfer is completed.
@@ -135,9 +146,11 @@ private:
typedef std::map< Raul::URI, SPtr<Interface> > Clients;
- Glib::Mutex _clients_mutex;
- Clients _clients;
- unsigned _bundle_depth;
+ Glib::Mutex _clients_mutex;
+ Clients _clients;
+ std::set<Raul::URI> _broadcastees;
+ std::atomic<bool> _must_broadcast;
+ unsigned _bundle_depth;
};
} // namespace Server
diff --git a/src/server/Context.cpp b/src/server/Context.cpp
index 1be69fe4..2ac2ddc2 100644
--- a/src/server/Context.cpp
+++ b/src/server/Context.cpp
@@ -55,6 +55,12 @@ Context::Context(Engine& engine, ID id)
{}
bool
+Context::must_notify(const PortImpl* port) const
+{
+ return port->is_monitored() || _engine.broadcaster()->must_broadcast();
+}
+
+bool
Context::notify(LV2_URID key,
FrameTime time,
PortImpl* port,
diff --git a/src/server/Context.hpp b/src/server/Context.hpp
index 028ee126..ea3593b8 100644
--- a/src/server/Context.hpp
+++ b/src/server/Context.hpp
@@ -53,6 +53,14 @@ public:
virtual ~Context() {}
+ /** Return true iff the given port should broadcast its value.
+ *
+ * Whether or not broadcasting is actually done is a per-client property,
+ * this is for use in the audio thread to quickly determine if the
+ * necessary calculations need to be done at all.
+ */
+ bool must_notify(const PortImpl* port) const;
+
/** Send a notification from this run context.
* @return false on failure (ring is full)
*/
diff --git a/src/server/DuplexPort.cpp b/src/server/DuplexPort.cpp
index 34c9b590..65152d02 100644
--- a/src/server/DuplexPort.cpp
+++ b/src/server/DuplexPort.cpp
@@ -100,9 +100,8 @@ DuplexPort::post_process(Context& context)
perspective. Mix down input delivered by plugins so output
(external perspective) is ready. */
InputPort::pre_process(context);
-
- if (_broadcast)
- broadcast_value(context, false);
+ } else {
+ monitor(context);
}
}
diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp
index 9002dbab..0d1a2d0e 100644
--- a/src/server/InputPort.cpp
+++ b/src/server/InputPort.cpp
@@ -124,9 +124,6 @@ void
InputPort::add_arc(ProcessContext& context, ArcImpl* c)
{
_arcs.push_front(*c);
- if (_type != PortType::CV) {
- _broadcast = true; // Broadcast value/activity of connected input
- }
}
/** Remove a arc. Realtime safe.
@@ -151,10 +148,6 @@ InputPort::remove_arc(ProcessContext& context, const OutputPort* tail)
return NULL;
}
- if (_arcs.empty()) {
- _broadcast = false; // Turn off broadcasting if no longer connected
- }
-
return arc;
}
@@ -220,8 +213,9 @@ InputPort::pre_process(Context& context)
}
}
- if (_broadcast)
- broadcast_value(context, false);
+ if (!_arcs.empty()) {
+ monitor(context);
+ }
}
void
diff --git a/src/server/OutputPort.cpp b/src/server/OutputPort.cpp
index 6b7329e5..492e5419 100644
--- a/src/server/OutputPort.cpp
+++ b/src/server/OutputPort.cpp
@@ -42,8 +42,6 @@ OutputPort::OutputPort(BufferFactory& bufs,
add_property(bufs.uris().rdf_type, bufs.uris().lv2_OutputPort);
}
- _broadcast = true;
-
setup_buffers(bufs, poly, false);
}
@@ -73,8 +71,7 @@ OutputPort::post_process(Context& context)
update_set_state(context, v);
}
- if (_broadcast)
- broadcast_value(context, false);
+ monitor(context);
}
} // namespace Server
diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp
index ed7a7084..352c8b23 100644
--- a/src/server/PortImpl.cpp
+++ b/src/server/PortImpl.cpp
@@ -51,12 +51,12 @@ PortImpl::PortImpl(BufferFactory& bufs,
, _value(value)
, _min(bufs.forge().make(0.0f))
, _max(bufs.forge().make(1.0f))
- , _last_broadcasted_value(value)
+ , _last_monitor_value(value)
, _set_states(new Raul::Array<SetState>(static_cast<size_t>(poly)))
, _prepared_set_states(NULL)
, _buffers(new Raul::Array<BufferRef>(static_cast<size_t>(poly)))
, _prepared_buffers(NULL)
- , _broadcast(false)
+ , _monitored(false)
, _set_by_user(false)
, _is_morph(false)
, _is_auto_morph(false)
@@ -338,8 +338,12 @@ PortImpl::clear_buffers()
}
void
-PortImpl::broadcast_value(Context& context, bool force)
+PortImpl::monitor(Context& context)
{
+ if (!context.must_notify(this)) {
+ return;
+ }
+
Forge& forge = context.engine().world()->forge();
URIs& uris = context.engine().world()->uris();
LV2_URID key = 0;
@@ -359,23 +363,34 @@ PortImpl::broadcast_value(Context& context, bool force)
case PortType::ATOM:
if (_buffer_type == _bufs.uris().atom_Sequence) {
LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)buffer(0)->atom();
- // TODO: Filter events, or only send one activity for blinkenlights
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
+ if (_monitored) {
+ // Monitoring explictly enabled, send everything
+ LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
+ context.notify(uris.ingen_activity,
+ context.start() + ev->time.frames,
+ this,
+ ev->body.size,
+ ev->body.type,
+ LV2_ATOM_BODY(&ev->body));
+ }
+ } else if (seq->atom.size > sizeof(LV2_Atom_Sequence_Body)) {
+ // Just sending for blinkenlights, send one
+ const int32_t one = 1;
context.notify(uris.ingen_activity,
- context.start() + ev->time.frames,
+ context.start(),
this,
- ev->body.size,
- ev->body.type,
- LV2_ATOM_BODY(&ev->body));
+ sizeof(int32_t),
+ (LV2_URID)uris.atom_Bool,
+ &one);
}
}
break;
}
- if (val.is_valid() && (force || val != _last_broadcasted_value)) {
+ if (val.is_valid() && val != _last_monitor_value) {
if (context.notify(key, context.start(), this,
val.size(), val.type(), val.get_body())) {
- _last_broadcasted_value = val;
+ _last_monitor_value = val;
}
/* On failure, last_broadcasted_value remains unaffected, so we'll try
diff --git a/src/server/PortImpl.hpp b/src/server/PortImpl.hpp
index 4aed4458..45918964 100644
--- a/src/server/PortImpl.hpp
+++ b/src/server/PortImpl.hpp
@@ -145,10 +145,18 @@ public:
void set_buffer_size(Context& context, BufferFactory& bufs, size_t size);
- void broadcast(bool b) { _broadcast = b; }
- bool broadcast() { return _broadcast; }
+ /** Return true iff this port is explicitly monitored.
+ *
+ * This is used for plugin UIs which require monitoring for particular
+ * ports, even if the Ingen client has not requested broadcasting in
+ * general (e.g. for canvas animation).
+ */
+ bool is_monitored() const { return _monitored; }
+
+ /** Explicitly turn on monitoring for this port. */
+ void enable_monitoring(bool monitored) { _monitored = monitored; }
- void broadcast_value(Context& context, bool force=false);
+ void monitor(Context& context);
void raise_set_by_user_flag() { _set_by_user = true; }
@@ -199,12 +207,12 @@ protected:
Raul::Atom _value;
Raul::Atom _min;
Raul::Atom _max;
- Raul::Atom _last_broadcasted_value;
+ Raul::Atom _last_monitor_value;
Raul::Array<SetState>* _set_states;
Raul::Array<SetState>* _prepared_set_states;
Raul::Array<BufferRef>* _buffers;
Raul::Array<BufferRef>* _prepared_buffers;
- bool _broadcast;
+ bool _monitored;
bool _set_by_user;
bool _is_morph;
bool _is_auto_morph;
diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp
index 9287f9e5..2b851b16 100644
--- a/src/server/events/Delta.cpp
+++ b/src/server/events/Delta.cpp
@@ -104,6 +104,7 @@ Delta::pre_process()
typedef Properties::const_iterator iterator;
const bool is_graph_object = Node::uri_is_path(_subject);
+ const bool is_client = (_subject == "ingen:/clients/this");
// Take a writer lock while we modify the store
Glib::RWLock::WriterLock lock(_engine.store()->lock());
@@ -112,7 +113,7 @@ Delta::pre_process()
? static_cast<Ingen::Resource*>(_engine.store()->get(Node::uri_to_path(_subject)))
: static_cast<Ingen::Resource*>(_engine.block_factory()->plugin(_subject));
- if (!_object && (!is_graph_object || !_create)) {
+ if (!_object && !is_client && (!is_graph_object || !_create)) {
return Event::pre_process_done(Status::NOT_FOUND, _subject);
}
@@ -155,7 +156,9 @@ Delta::pre_process()
if (port)
_old_bindings = _engine.control_bindings()->remove(port);
}
- _object->remove_property(key, value);
+ if (_object) {
+ _object->remove_property(key, value);
+ }
}
for (const auto& p : _properties) {
@@ -243,6 +246,9 @@ Delta::pre_process()
_status = Status::BAD_OBJECT_TYPE;
}
}
+ } else if (is_client && key == uris.ingen_broadcast) {
+ _engine.broadcaster()->set_broadcast(
+ _request_client->uri(), value.get_bool());
}
if (_status != Status::NOT_PREPARED) {
@@ -287,7 +293,7 @@ Delta::execute(ProcessContext& context)
switch (*t) {
case SpecialType::ENABLE_BROADCAST:
if (port) {
- port->broadcast(value.get_bool());
+ port->enable_monitoring(value.get_bool());
}
break;
case SpecialType::ENABLE:
diff --git a/src/server/internals/Controller.cpp b/src/server/internals/Controller.cpp
index e65319a0..cad0aac4 100644
--- a/src/server/internals/Controller.cpp
+++ b/src/server/internals/Controller.cpp
@@ -118,7 +118,7 @@ ControllerNode::control(ProcessContext& context, uint8_t control_num, uint8_t va
// FIXME: not thread safe
_param_port->set_value(context.engine().world()->forge().make(control_num));
_param_port->set_control_value(context, time, control_num);
- _param_port->broadcast_value(context, true);
+ _param_port->monitor(context);
_learning = false;
}
diff --git a/src/server/internals/Trigger.cpp b/src/server/internals/Trigger.cpp
index 41e1800f..c1c00b6b 100644
--- a/src/server/internals/Trigger.cpp
+++ b/src/server/internals/Trigger.cpp
@@ -133,7 +133,7 @@ TriggerNode::note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity
// FIXME: not thread safe
_note_port->set_value(context.engine().world()->forge().make((float)note_num));
_note_port->set_control_value(context, time, (float)note_num);
- _note_port->broadcast_value(context, true);
+ _note_port->monitor(context);
_learning = false;
}