diff options
author | David Robillard <d@drobilla.net> | 2013-02-02 02:16:23 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2013-02-02 02:16:23 +0000 |
commit | d049b582e1db60ee0f6fd02a40202145488c7288 (patch) | |
tree | 4b30ba2522a14863ce76f672f537dcca0c14c34e /src/server | |
parent | 73a01c1bd8d6cf92522a433cd2b0bd491f2af99a (diff) | |
download | ingen-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.cpp | 18 | ||||
-rw-r--r-- | src/server/Broadcaster.hpp | 21 | ||||
-rw-r--r-- | src/server/Context.cpp | 6 | ||||
-rw-r--r-- | src/server/Context.hpp | 8 | ||||
-rw-r--r-- | src/server/DuplexPort.cpp | 5 | ||||
-rw-r--r-- | src/server/InputPort.cpp | 12 | ||||
-rw-r--r-- | src/server/OutputPort.cpp | 5 | ||||
-rw-r--r-- | src/server/PortImpl.cpp | 37 | ||||
-rw-r--r-- | src/server/PortImpl.hpp | 18 | ||||
-rw-r--r-- | src/server/events/Delta.cpp | 12 | ||||
-rw-r--r-- | src/server/internals/Controller.cpp | 2 | ||||
-rw-r--r-- | src/server/internals/Trigger.cpp | 2 |
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; } |