From 0a9297ed2a1622d252a389d8babc0656fedbe7fd Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 15 Aug 2012 04:18:31 +0000 Subject: Simpler and more unified EnginePort implementation. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4699 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/DirectDriver.hpp | 9 +- src/server/Driver.hpp | 31 ++-- src/server/EnginePort.hpp | 40 ++--- src/server/JackDriver.cpp | 308 ++++++++++++++++++--------------------- src/server/JackDriver.hpp | 44 ++---- src/server/events/Delete.cpp | 10 +- src/server/events/Delete.hpp | 1 - src/server/events/Disconnect.hpp | 1 - src/server/events/Move.cpp | 2 +- src/server/ingen_lv2.cpp | 167 +++++++++------------ 10 files changed, 262 insertions(+), 351 deletions(-) diff --git a/src/server/DirectDriver.hpp b/src/server/DirectDriver.hpp index ccf65fee..76cd3cbc 100644 --- a/src/server/DirectDriver.hpp +++ b/src/server/DirectDriver.hpp @@ -42,17 +42,16 @@ public: return NULL; } - virtual EnginePort* port(const Raul::Path& path) { return NULL; } + virtual EnginePort* get_port(const Raul::Path& path) { return NULL; } virtual void add_port(ProcessContext& context, EnginePort* port) {} + virtual void remove_port(ProcessContext& context, EnginePort* port) {} virtual void rename_port(const Raul::Path& old_path, const Raul::Path& new_path) {} - virtual Raul::Deletable* remove_port(ProcessContext& context, - EnginePort* port) { - return NULL; - } + virtual void register_port(EnginePort& port) {} + virtual void unregister_port(EnginePort& port) {} virtual SampleCount block_length() const { return _block_length; } diff --git a/src/server/Driver.hpp b/src/server/Driver.hpp index e551f636..1d6e7ef0 100644 --- a/src/server/Driver.hpp +++ b/src/server/Driver.hpp @@ -17,13 +17,12 @@ #ifndef INGEN_ENGINE_DRIVER_HPP #define INGEN_ENGINE_DRIVER_HPP -#include +#include -#include - -#include "raul/Deletable.hpp" +#include "raul/Noncopyable.hpp" #include "DuplexPort.hpp" +#include "EnginePort.hpp" namespace Raul { class Path; } @@ -33,15 +32,15 @@ namespace Server { class DuplexPort; class EnginePort; -/** Driver abstract base class. +/** Engine driver base class. * * A Driver is, from the perspective of GraphObjects (nodes, patches, ports) an * interface for managing system ports. An implementation of Driver basically - * needs to manage DriverPorts, and handle writing/reading data to/from them. + * needs to manage EnginePorts, and handle writing/reading data to/from them. * * \ingroup engine */ -class Driver : boost::noncopyable { +class Driver : public Raul::Noncopyable { public: virtual ~Driver() {} @@ -57,14 +56,24 @@ public: virtual EnginePort* create_port(DuplexPort* patch_port) = 0; /** Find a system port by path. */ - virtual EnginePort* port(const Raul::Path& path) = 0; + virtual EnginePort* get_port(const Raul::Path& path) = 0; /** Add a system visible port (e.g. a port on the root patch). */ virtual void add_port(ProcessContext& context, EnginePort* port) = 0; - /** Remove a system visible port. */ - virtual Raul::Deletable* remove_port(ProcessContext& context, - EnginePort* port) = 0; + /** Remove a system visible port. + * + * This removes the port from the driver in the process thread but does not + * destroy the port. To actually remove the system port, unregister_port() + * must be called later in another thread. + */ + virtual void remove_port(ProcessContext& context, EnginePort* port) = 0; + + /** Register a system visible port. */ + virtual void register_port(EnginePort& port) = 0; + + /** Register a system visible port. */ + virtual void unregister_port(EnginePort& port) = 0; /** Rename a system visible port. */ virtual void rename_port(const Raul::Path& old_path, diff --git a/src/server/EnginePort.hpp b/src/server/EnginePort.hpp index c911c118..3bda2998 100644 --- a/src/server/EnginePort.hpp +++ b/src/server/EnginePort.hpp @@ -17,53 +17,43 @@ #ifndef INGEN_ENGINE_ENGINE_PORT_HPP #define INGEN_ENGINE_ENGINE_PORT_HPP -#include - #include "raul/Deletable.hpp" #include "raul/Noncopyable.hpp" -#include "DuplexPort.hpp" +#include -namespace Raul { class Path; } +#include "DuplexPort.hpp" namespace Ingen { namespace Server { -class DuplexPort; -class ProcessContext; - -/** Representation of a "system" port (e.g. a Jack port). - * - * This is the class through which the rest of the engine manages everything - * related to driver ports. Derived classes are expected to have a pointer to - * their driver (to be able to perform the operation necessary). +/** A "system" port (e.g. a Jack port, an external port on Ingen). * - * \ingroup engine + * @ingroup engine */ -class EnginePort : public Raul::Noncopyable, public Raul::Deletable { +class EnginePort : public Raul::Noncopyable + , public Raul::Deletable + , public boost::intrusive::list_base_hook<> +{ public: explicit EnginePort(DuplexPort* port) : _patch_port(port) , _buffer(NULL) + , _handle(NULL) {} - virtual ~EnginePort() {} + void set_buffer(void* buf) { _buffer = buf; } + void set_handle(void* buf) { _handle = buf; } - /** Create system port */ - virtual void create() {} - - /** Destroy system port */ - virtual void destroy() {} - - void* buffer() const { return _buffer; } - void set_buffer(void* buf) { _buffer = buf; } - - bool is_input() const { return _patch_port->is_input(); } + void* buffer() const { return _buffer; } + void* handle() const { return _handle; } DuplexPort* patch_port() const { return _patch_port; } + bool is_input() const { return _patch_port->is_input(); } protected: DuplexPort* _patch_port; void* _buffer; + void* _handle; }; } // namespace Server diff --git a/src/server/JackDriver.cpp b/src/server/JackDriver.cpp index 65566472..31f19032 100644 --- a/src/server/JackDriver.cpp +++ b/src/server/JackDriver.cpp @@ -30,7 +30,6 @@ #include "ingen/LV2Features.hpp" #include "ingen/World.hpp" #include "lv2/lv2plug.in/ns/ext/atom/util.h" -#include "raul/List.hpp" #include "raul/log.hpp" #include "Buffer.hpp" @@ -51,123 +50,6 @@ typedef jack_default_audio_sample_t jack_sample_t; namespace Ingen { namespace Server { -//// JackPort //// - -JackPort::JackPort(JackDriver* driver, DuplexPort* patch_port) - : EnginePort(patch_port) - , Raul::List::Node(this) - , _driver(driver) - , _jack_port(NULL) -{ - patch_port->setup_buffers(*driver->_engine.buffer_factory(), - patch_port->poly(), - false); - create(); -} - -JackPort::~JackPort() -{ - assert(_jack_port == NULL); -} - -void -JackPort::create() -{ - _jack_port = jack_port_register( - _driver->jack_client(), - _patch_port->path().substr(1).c_str(), - (_patch_port->is_a(PortType::AUDIO)) - ? JACK_DEFAULT_AUDIO_TYPE : JACK_DEFAULT_MIDI_TYPE, - (_patch_port->is_input()) - ? JackPortIsInput : JackPortIsOutput, - 0); - - if (_jack_port == NULL) { - LOG(Raul::error)(Raul::fmt("Failed to register port %1%\n") - % _patch_port->path().c_str()); - throw JackDriver::PortRegistrationFailedException(); - } -} - -void -JackPort::destroy() -{ - assert(_jack_port); - if (jack_port_unregister(_driver->jack_client(), _jack_port)) - LOG(Raul::error)("Unable to unregister port\n"); - _jack_port = NULL; -} - -void -JackPort::pre_process(ProcessContext& context) -{ - const SampleCount nframes = context.nframes(); - _buffer = jack_port_get_buffer(_jack_port, nframes); - - if (!is_input()) { - _patch_port->buffer(0)->clear(); - return; - } - - if (_patch_port->is_a(PortType::AUDIO)) { - Buffer* patch_buf = _patch_port->buffer(0).get(); - memcpy(patch_buf->samples(), _buffer, nframes * sizeof(float)); - - } else if (_patch_port->buffer_type() == _patch_port->bufs().uris().atom_Sequence) { - Buffer* patch_buf = (Buffer*)_patch_port->buffer(0).get(); - - const jack_nframes_t event_count = jack_midi_get_event_count(_buffer); - - patch_buf->prepare_write(context); - - // Copy events from Jack port buffer into patch port buffer - for (jack_nframes_t i = 0; i < event_count; ++i) { - jack_midi_event_t ev; - jack_midi_event_get(&ev, _buffer, i); - - if (!patch_buf->append_event( - ev.time, ev.size, _driver->_midi_event_type, ev.buffer)) { - LOG(Raul::warn)("Failed to write to MIDI buffer, events lost!\n"); - } - } - } -} - -void -JackPort::post_process(ProcessContext& context) -{ - const SampleCount nframes = context.nframes(); - if (is_input()) { - return; - } - - if (!_buffer) { - // First cycle for a new output, so pre_process wasn't called - _buffer = jack_port_get_buffer(_jack_port, nframes); - } - - _patch_port->post_process(context); - if (_patch_port->is_a(PortType::AUDIO)) { - Buffer* patch_buf = _patch_port->buffer(0).get(); - memcpy(_buffer, patch_buf->samples(), nframes * sizeof(Sample)); - - } else if (_patch_port->buffer_type() == _patch_port->bufs().uris().atom_Sequence) { - Buffer* patch_buf = _patch_port->buffer(0).get(); - - jack_midi_clear_buffer(_buffer); - - LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)patch_buf->atom(); - LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { - const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); - if (ev->body.type == _patch_port->bufs().uris().midi_MidiEvent) { - jack_midi_event_write(_buffer, ev->time.frames, buf, ev->body.size); - } - } - } -} - -//// JackDriver //// - JackDriver::JackDriver(Engine& engine) : _engine(engine) , _sem(0) @@ -243,8 +125,9 @@ JackDriver::attach(const std::string& server_name, jack_set_session_callback(_client, session_cb, this); #endif - for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) - (*i)->create(); + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + register_port(*i); + } return true; } @@ -283,8 +166,9 @@ JackDriver::deactivate() _is_activated = false; _sem.wait(); - for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) - (*i)->destroy(); + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + unregister_port(*i); + } if (_client) { jack_deactivate(_client); @@ -298,74 +182,156 @@ JackDriver::deactivate() } } -/** Add a Jack port. - * - * Realtime safe, this is to be called at the beginning of a process cycle to - * insert (and actually begin using) a new port. - * - * See create_port() and remove_port(). - */ +EnginePort* +JackDriver::get_port(const Raul::Path& path) +{ + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + if (i->patch_port()->path() == path) { + return &*i; + } + } + + return NULL; +} + void JackDriver::add_port(ProcessContext& context, EnginePort* port) { - assert(dynamic_cast(port)); - _ports.push_back((JackPort*)port); + _ports.push_back(*port); } -/** Remove a Jack port. - * - * Realtime safe. This is to be called at the beginning of a process cycle to - * remove the port from the lists read by the audio thread, so the port - * will no longer be used and can be removed afterwards. - * - * It is the callers responsibility to delete the returned port. - */ -Raul::Deletable* -JackDriver::remove_port(ProcessContext& context, - EnginePort* port) +void +JackDriver::remove_port(ProcessContext& context, EnginePort* port) { - for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) { - if (*i == port) { - return _ports.erase(i); - } + _ports.erase(_ports.iterator_to(*port)); +} + +void +JackDriver::register_port(EnginePort& port) +{ + jack_port_t* jack_port = jack_port_register( + _client, + port.patch_port()->path().substr(1).c_str(), + (port.patch_port()->is_a(PortType::AUDIO) + ? JACK_DEFAULT_AUDIO_TYPE : JACK_DEFAULT_MIDI_TYPE), + (port.patch_port()->is_input() + ? JackPortIsInput : JackPortIsOutput), + 0); + + if (!jack_port) { + throw JackDriver::PortRegistrationFailedException(); } - return NULL; + port.set_handle(jack_port); +} + +void +JackDriver::unregister_port(EnginePort& port) +{ + if (jack_port_unregister(_client, (jack_port_t*)port.handle())) { + LOG(Raul::error)("Failed to unregister Jack port\n"); + } } void JackDriver::rename_port(const Raul::Path& old_path, const Raul::Path& new_path) { - JackPort* jport = dynamic_cast(port(old_path)); - if (jport) { - jack_port_set_name(jport->jack_port(), new_path.substr(1).c_str()); + EnginePort* eport = get_port(old_path); + if (eport) { + jack_port_set_name((jack_port_t*)eport->handle(), + new_path.substr(1).c_str()); } } EnginePort* -JackDriver::port(const Raul::Path& path) +JackDriver::create_port(DuplexPort* patch_port) { - for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) - if ((*i)->patch_port()->path() == path) - return (*i); + if (patch_port && + (patch_port->is_a(PortType::AUDIO) || + (patch_port->is_a(PortType::ATOM) && + patch_port->buffer_type() == _engine.world()->uris().atom_Sequence))) { + EnginePort* eport = new EnginePort(patch_port); + register_port(*eport); + patch_port->setup_buffers(*_engine.buffer_factory(), + patch_port->poly(), + false); + return eport; + } else { + return NULL; + } +} - return NULL; +void +JackDriver::pre_process_port(ProcessContext& context, EnginePort* port) +{ + const SampleCount nframes = context.nframes(); + jack_port_t* jack_port = (jack_port_t*)port->handle(); + PortImpl* patch_port = port->patch_port(); + void* buffer = jack_port_get_buffer(jack_port, nframes); + + port->set_buffer(buffer); + + if (!patch_port->is_input()) { + patch_port->buffer(0)->clear(); + return; + } + + if (patch_port->is_a(PortType::AUDIO)) { + Buffer* patch_buf = patch_port->buffer(0).get(); + memcpy(patch_buf->samples(), buffer, nframes * sizeof(float)); + + } else if (patch_port->buffer_type() == patch_port->bufs().uris().atom_Sequence) { + Buffer* patch_buf = (Buffer*)patch_port->buffer(0).get(); + + const jack_nframes_t event_count = jack_midi_get_event_count(buffer); + + patch_buf->prepare_write(context); + + // Copy events from Jack port buffer into patch port buffer + for (jack_nframes_t i = 0; i < event_count; ++i) { + jack_midi_event_t ev; + jack_midi_event_get(&ev, buffer, i); + + if (!patch_buf->append_event( + ev.time, ev.size, _midi_event_type, ev.buffer)) { + LOG(Raul::warn)("Failed to write to MIDI buffer, events lost!\n"); + } + } + } } -EnginePort* -JackDriver::create_port(DuplexPort* patch_port) +void +JackDriver::post_process_port(ProcessContext& context, EnginePort* port) { - try { - if (patch_port->is_a(PortType::AUDIO) - || (patch_port->is_a(PortType::ATOM) && - patch_port->buffer_type() == patch_port->bufs().uris().atom_Sequence)) { - return new JackPort(this, patch_port); - } else { - return NULL; + const SampleCount nframes = context.nframes(); + jack_port_t* jack_port = (jack_port_t*)port->handle(); + PortImpl* patch_port = port->patch_port(); + void* buffer = port->buffer(); + + if (patch_port->is_input()) { + return; + } + + if (!buffer) { + // First cycle for a new output, so pre_process wasn't called + buffer = jack_port_get_buffer(jack_port, nframes); + port->set_buffer(buffer); + } + + patch_port->post_process(context); + Buffer* const patch_buf = patch_port->buffer(0).get(); + if (patch_port->is_a(PortType::AUDIO)) { + memcpy(buffer, patch_buf->samples(), nframes * sizeof(Sample)); + } else if (patch_port->buffer_type() == patch_port->bufs().uris().atom_Sequence) { + jack_midi_clear_buffer(buffer); + LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)patch_buf->atom(); + LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { + const uint8_t* buf = (const uint8_t*)LV2_ATOM_BODY(&ev->body); + if (ev->body.type == patch_port->bufs().uris().midi_MidiEvent) { + jack_midi_event_write(buffer, ev->time.frames, buf, ev->body.size); + } } - } catch (...) { - return NULL; } } @@ -394,14 +360,16 @@ JackDriver::_process_cb(jack_nframes_t nframes) _engine.process_context().locate(start_of_current_cycle, nframes); // Read input - for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) - (*i)->pre_process(_engine.process_context()); + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + pre_process_port(_engine.process_context(), &*i); + } _engine.run(nframes); // Write output - for (Raul::List::iterator i = _ports.begin(); i != _ports.end(); ++i) - (*i)->post_process(_engine.process_context()); + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + post_process_port(_engine.process_context(), &*i); + } return 0; } diff --git a/src/server/JackDriver.hpp b/src/server/JackDriver.hpp index 5724afa7..93f24ece 100644 --- a/src/server/JackDriver.hpp +++ b/src/server/JackDriver.hpp @@ -29,7 +29,6 @@ #endif #include "raul/AtomicInt.hpp" -#include "raul/List.hpp" #include "raul/Semaphore.hpp" #include "raul/Thread.hpp" @@ -47,29 +46,6 @@ class PortImpl; class DuplexPort; class JackDriver; -/** Used internally by JackDriver to represent a Jack port. - * - * A Jack port always has a one-to-one association with a Patch port. - */ -class JackPort : public EnginePort, public Raul::List::Node -{ -public: - JackPort(JackDriver* driver, DuplexPort* patch_port); - ~JackPort(); - - void create(); - void destroy(); - - void pre_process(ProcessContext& context); - void post_process(ProcessContext& context); - - jack_port_t* jack_port() const { return _jack_port; } - -private: - JackDriver* _driver; - jack_port_t* _jack_port; -}; - /** The Jack Driver. * * The process callback here drives the entire audio thread by "pulling" @@ -93,16 +69,14 @@ public: void enable(); void disable(); - EnginePort* port(const Raul::Path& path); EnginePort* create_port(DuplexPort* patch_port); + EnginePort* get_port(const Raul::Path& path); + void rename_port(const Raul::Path& old_path, const Raul::Path& new_path); void add_port(ProcessContext& context, EnginePort* port); - - void rename_port(const Raul::Path& old_path, - const Raul::Path& new_path); - - Raul::Deletable* remove_port(ProcessContext& context, - EnginePort* port); + void remove_port(ProcessContext& context, EnginePort* port); + void register_port(EnginePort& port); + void unregister_port(EnginePort& port); /** Transport state for this frame. * Intended to only be called from the audio thread. */ @@ -141,6 +115,9 @@ private: } #endif + void pre_process_port(ProcessContext& context, EnginePort* port); + void post_process_port(ProcessContext& context, EnginePort* port); + // Non static callbacks (methods) void _thread_init_cb(); void _shutdown_cb(); @@ -150,7 +127,11 @@ private: void _session_cb(jack_session_event_t* event); #endif +protected: + typedef boost::intrusive::list Ports; + Engine& _engine; + Ports _ports; std::list< SharedPtr > _jack_threads; Raul::Semaphore _sem; Raul::AtomicInt _flag; @@ -161,7 +142,6 @@ private: bool _is_activated; jack_position_t _position; jack_transport_state_t _transport_state; - Raul::List _ports; }; } // namespace Server diff --git a/src/server/events/Delete.cpp b/src/server/events/Delete.cpp index 97f1161f..84b29a6f 100644 --- a/src/server/events/Delete.cpp +++ b/src/server/events/Delete.cpp @@ -41,7 +41,6 @@ Delete::Delete(Engine& engine, const Raul::URI& uri) : Event(engine, client, id, time) , _uri(uri) - , _garbage(NULL) , _engine_port(NULL) , _patch_node_listnode(NULL) , _patch_port_listnode(NULL) @@ -111,7 +110,7 @@ Delete::pre_process() } if (!_port->parent_patch()->parent()) { - _engine_port = _engine.driver()->port(_port->path()); + _engine_port = _engine.driver()->get_port(_port->path()); } } @@ -145,7 +144,7 @@ Delete::execute(ProcessContext& context) _port->parent_patch()->external_ports(_ports_array); if (_engine_port) { - _garbage = _engine.driver()->remove_port(context, _engine_port); + _engine.driver()->remove_port(context, _engine_port); } } @@ -177,10 +176,9 @@ Delete::post_process() } if (_engine_port) { - _engine_port->destroy(); + _engine.driver()->unregister_port(*_engine_port); + delete _engine_port; } - - delete _garbage; } } // namespace Events diff --git a/src/server/events/Delete.hpp b/src/server/events/Delete.hpp index 53671846..a493fcf7 100644 --- a/src/server/events/Delete.hpp +++ b/src/server/events/Delete.hpp @@ -73,7 +73,6 @@ private: Raul::Path _path; SharedPtr _node; ///< Non-NULL iff a node SharedPtr _port; ///< Non-NULL iff a port - Raul::Deletable* _garbage; EnginePort* _engine_port; PatchImpl::Nodes::Node* _patch_node_listnode; Raul::List::Node* _patch_port_listnode; diff --git a/src/server/events/Disconnect.hpp b/src/server/events/Disconnect.hpp index bcd8f1bc..b008025a 100644 --- a/src/server/events/Disconnect.hpp +++ b/src/server/events/Disconnect.hpp @@ -24,7 +24,6 @@ #include "BufferFactory.hpp" namespace Raul { -template class ListNode; template class Array; } diff --git a/src/server/events/Move.cpp b/src/server/events/Move.cpp index 4d72e9ba..5fa58825 100644 --- a/src/server/events/Move.cpp +++ b/src/server/events/Move.cpp @@ -65,7 +65,7 @@ Move::pre_process() return Event::pre_process_done(EXISTS, _new_path); } - EnginePort* eport = _engine.driver()->port(_old_path); + EnginePort* eport = _engine.driver()->get_port(_old_path); if (eport) { _engine.driver()->rename_port(_old_path, _new_path); } diff --git a/src/server/ingen_lv2.cpp b/src/server/ingen_lv2.cpp index a28eb5fc..af0983fb 100644 --- a/src/server/ingen_lv2.cpp +++ b/src/server/ingen_lv2.cpp @@ -81,36 +81,52 @@ namespace Server { class LV2Driver; -void enqueue_message( - ProcessContext& context, LV2Driver* driver, const LV2_Atom* msg); - void signal_main(ProcessContext& context, LV2Driver* driver); -class LV2Port : public EnginePort +class LV2Driver : public Ingen::Server::Driver + , public Ingen::AtomSink { public: - LV2Port(LV2Driver* driver, DuplexPort* patch_port) - : EnginePort(patch_port) - , _driver(driver) + LV2Driver(Engine& engine, SampleCount block_length, SampleCount sample_rate) + : _engine(engine) + , _main_sem(0) + , _reader(engine.world()->uri_map(), + engine.world()->uris(), + engine.world()->forge(), + *engine.world()->interface().get()) + , _writer(engine.world()->uri_map(), + engine.world()->uris(), + *this) + , _from_ui(block_length * sizeof(float)) // FIXME: size + , _to_ui(block_length * sizeof(float)) // FIXME: size + , _root_patch(NULL) + , _block_length(block_length) + , _sample_rate(sample_rate) + , _frame_time(0) + , _to_ui_overflow_sem(0) + , _to_ui_overflow(false) {} - void pre_process(ProcessContext& context) { - if (!is_input() || !_buffer) { + void pre_process_port(ProcessContext& context, EnginePort* port) { + PortImpl* patch_port = port->patch_port(); + void* buffer = port->buffer(); + + if (!patch_port->is_input() || !buffer) { return; } - Buffer* const patch_buf = _patch_port->buffer(0).get(); - if (_patch_port->is_a(PortType::AUDIO) || - _patch_port->is_a(PortType::CV)) { + Buffer* const patch_buf = patch_port->buffer(0).get(); + if (patch_port->is_a(PortType::AUDIO) || + patch_port->is_a(PortType::CV)) { memcpy(patch_buf->samples(), - _buffer, + buffer, context.nframes() * sizeof(float)); - } else if (_patch_port->is_a(PortType::CONTROL)) { - patch_buf->samples()[0] = ((float*)_buffer)[0]; + } else if (patch_port->is_a(PortType::CONTROL)) { + patch_buf->samples()[0] = ((float*)buffer)[0]; } else { - LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)_buffer; + LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)buffer; bool enqueued = false; - URIs& uris = _patch_port->bufs().uris(); + URIs& uris = patch_port->bufs().uris(); patch_buf->prepare_write(context); LV2_ATOM_SEQUENCE_FOREACH(seq, ev) { if (!patch_buf->append_event( @@ -120,73 +136,46 @@ public: } if (AtomReader::is_message(uris, &ev->body)) { - enqueue_message(context, _driver, &ev->body); + enqueue_message(&ev->body); enqueued = true; } } if (enqueued) { - signal_main(context, _driver); + _main_sem.post(); } } } - void post_process(ProcessContext& context) { - if (is_input() || !_buffer) { + void post_process_port(ProcessContext& context, EnginePort* port) { + PortImpl* patch_port = port->patch_port(); + void* buffer = port->buffer(); + + if (patch_port->is_input() || !buffer) { return; } - Buffer* patch_buf = _patch_port->buffer(0).get(); - if (_patch_port->is_a(PortType::AUDIO) || - _patch_port->is_a(PortType::CV)) { - memcpy(_buffer, + Buffer* patch_buf = patch_port->buffer(0).get(); + if (patch_port->is_a(PortType::AUDIO) || + patch_port->is_a(PortType::CV)) { + memcpy(buffer, patch_buf->samples(), context.nframes() * sizeof(float)); - } else if (_patch_port->is_a(PortType::CONTROL)) { - ((float*)_buffer)[0] = patch_buf->samples()[0]; + } else if (patch_port->is_a(PortType::CONTROL)) { + ((float*)buffer)[0] = patch_buf->samples()[0]; } else { - memcpy(_buffer, + memcpy(buffer, patch_buf->atom(), sizeof(LV2_Atom) + patch_buf->atom()->size); } } -private: - LV2Driver* _driver; -}; - -class LV2Driver : public Ingen::Server::Driver - , public Ingen::AtomSink -{ -private: - typedef std::vector Ports; - -public: - LV2Driver(Engine& engine, SampleCount block_length, SampleCount sample_rate) - : _engine(engine) - , _main_sem(0) - , _reader(engine.world()->uri_map(), - engine.world()->uris(), - engine.world()->forge(), - *engine.world()->interface().get()) - , _writer(engine.world()->uri_map(), - engine.world()->uris(), - *this) - , _from_ui(block_length * sizeof(float)) // FIXME: size - , _to_ui(block_length * sizeof(float)) // FIXME: size - , _root_patch(NULL) - , _block_length(block_length) - , _sample_rate(sample_rate) - , _frame_time(0) - , _to_ui_overflow_sem(0) - , _to_ui_overflow(false) - {} - void run(uint32_t nframes) { _engine.process_context().locate(_frame_time, nframes); - for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) - (*i)->pre_process(_engine.process_context()); + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + pre_process_port(_engine.process_context(), *i); + } _engine.run(nframes); if (_engine.post_processor()->pending()) { @@ -195,8 +184,9 @@ public: flush_to_ui(); - for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) - (*i)->post_process(_engine.process_context()); + for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { + post_process_port(_engine.process_context(), *i); + } _frame_time += nframes; } @@ -209,45 +199,34 @@ public: virtual void set_root_patch(PatchImpl* patch) { _root_patch = patch; } virtual PatchImpl* root_patch() { return _root_patch; } - virtual EnginePort* engine_port(ProcessContext& context, - const Raul::Path& path) { + virtual EnginePort* get_port(const Raul::Path& path) { for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((*i)->patch_port()->path() == path) { - return (*i); + return *i; } } return NULL; } - EnginePort* port(const Raul::Path& path) { return NULL; } + /** Unused since LV2 has no dynamic ports. */ + virtual void add_port(ProcessContext& context, EnginePort* port) {} - /** Doesn't have to be real-time safe since LV2 has no dynamic ports. */ - virtual void add_port(ProcessContext& context, EnginePort* port) { - assert(dynamic_cast(port)); - assert(port->patch_port()->index() == _ports.size()); - _ports.push_back((LV2Port*)port); - } + /** Unused since LV2 has no dynamic ports. */ + virtual void remove_port(ProcessContext& context, EnginePort* port) {} - /** Doesn't have to be real-time safe since LV2 has no dynamic ports. */ - virtual Raul::Deletable* remove_port(ProcessContext& context, - EnginePort* port) { - for (Ports::iterator i = _ports.begin(); i != _ports.end(); ++i) { - if (*i == port) { - _ports.erase(i); - return NULL; - } - } + /** Unused since LV2 has no dynamic ports. */ + virtual void register_port(EnginePort& port) {} - return NULL; - } + /** Unused since LV2 has no dynamic ports. */ + virtual void unregister_port(EnginePort& port) {} - /** UNused since LV2 has no dynamic ports. */ + /** Unused since LV2 has no dynamic ports. */ virtual void rename_port(const Raul::Path& old_path, const Raul::Path& new_path) {} virtual EnginePort* create_port(DuplexPort* patch_port) { - return new LV2Port(this, patch_port); + return new EnginePort(patch_port); } /** Called in run thread for events received at control input port. */ @@ -354,10 +333,13 @@ public: AtomReader& reader() { return _reader; } AtomWriter& writer() { return _writer; } + typedef std::vector Ports; + Ports& ports() { return _ports; } private: Engine& _engine; + Ports _ports; Raul::Semaphore _main_sem; AtomReader _reader; AtomWriter _writer; @@ -367,23 +349,10 @@ private: SampleCount _block_length; SampleCount _sample_rate; SampleCount _frame_time; - Ports _ports; Raul::Semaphore _to_ui_overflow_sem; bool _to_ui_overflow; }; -void -enqueue_message(ProcessContext& context, LV2Driver* driver, const LV2_Atom* msg) -{ - driver->enqueue_message(msg); -} - -void -signal_main(ProcessContext& context, LV2Driver* driver) -{ - driver->main_sem().post(); -} - } // namespace Server } // namespace Ingen -- cgit v1.2.1