diff options
author | David Robillard <d@drobilla.net> | 2010-02-20 21:52:36 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2010-02-20 21:52:36 +0000 |
commit | 46e5de590817756b21a7a5d99bd4963df343f455 (patch) | |
tree | 7d7b3b63297b24d84e5b42cc8aeb22d4212738b5 | |
parent | b96a4015ae39b5bdd9afbd82898c0168a0a8e613 (diff) | |
download | ingen-46e5de590817756b21a7a5d99bd4963df343f455.tar.gz ingen-46e5de590817756b21a7a5d99bd4963df343f455.tar.bz2 ingen-46e5de590817756b21a7a5d99bd4963df343f455.zip |
Heavy overhaul of buffer management and polyphony.
* Working polyphony when nodes are instantiated at desired polyphony
level (dynamic still doesn't work)
* Use shared silent buffer for disconnected audio inputs (save memory)
* Eliminate redundant patch compiling on delete and disconnect-all
events that have child events
* Fix a ton of crash bugs and other issues I've since forgotten
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2468 a436a847-0d15-0410-975c-d299462d15a1
74 files changed, 787 insertions, 634 deletions
diff --git a/src/client/ClientStore.cpp b/src/client/ClientStore.cpp index b12cdd7b..8a6e008b 100644 --- a/src/client/ClientStore.cpp +++ b/src/client/ClientStore.cpp @@ -249,10 +249,10 @@ void ClientStore::put(const URI& uri, const Resource::Properties& properties) { typedef Resource::Properties::const_iterator iterator; - LOG(debug) << "PUT " << uri << " {" << endl; + /*LOG(info) << "PUT " << uri << " {" << endl; for (iterator i = properties.begin(); i != properties.end(); ++i) - LOG(debug) << " " << i->first << " = " << i->second << " :: " << i->second.type() << endl; - LOG(debug) << "}" << endl; + LOG(info) << " " << i->first << " = " << i->second << " :: " << i->second.type() << endl; + LOG(info) << "}" << endl;*/ bool is_path = Path::is_valid(uri.str()); bool is_meta = ResourceImpl::is_meta_uri(uri); @@ -292,11 +292,7 @@ ClientStore::put(const URI& uri, const Resource::Properties& properties) ResourceImpl::type(properties, is_patch, is_node, is_port, is_output, data_type); if (is_patch) { - uint32_t poly = 1; - iterator p = properties.find(uris.ingen_polyphony); - if (p != properties.end() && p->second.is_valid() && p->second.type() == Atom::INT) - poly = p->second.get_int32(); - SharedPtr<PatchModel> model(new PatchModel(path, poly)); + SharedPtr<PatchModel> model(new PatchModel(path)); model->set_properties(properties); add_object(model); } else if (is_node) { @@ -340,6 +336,13 @@ ClientStore::put(const URI& uri, const Resource::Properties& properties) void ClientStore::delta(const URI& uri, const Resource::Properties& remove, const Resource::Properties& add) { + typedef Resource::Properties::const_iterator iterator; + /*LOG(info) << "DELTA " << uri << " {" << endl; + for (iterator i = remove.begin(); i != remove.end(); ++i) + LOG(info) << " - " << i->first << " = " << i->second << " :: " << i->second.type() << endl; + for (iterator i = add.begin(); i != add.end(); ++i) + LOG(info) << " + " << i->first << " = " << i->second << " :: " << i->second.type() << endl; + LOG(info) << "}" << endl;*/ bool is_meta = ResourceImpl::is_meta_uri(uri); string path_str = is_meta ? (string("/") + uri.chop_start("#")) : uri.str(); if (!Path::is_valid(path_str)) { diff --git a/src/client/PatchModel.cpp b/src/client/PatchModel.cpp index 7d44eb1c..bf4168d6 100644 --- a/src/client/PatchModel.cpp +++ b/src/client/PatchModel.cpp @@ -169,22 +169,19 @@ PatchModel::enabled() const } -Raul::Atom& -PatchModel::set_meta_property(const Raul::URI& key, const Atom& value) +uint32_t +PatchModel::internal_poly() const { - if (key == Shared::LV2URIMap::instance().ingen_polyphony) - _poly = value.get_int32(); - - return NodeModel::set_meta_property(key, value); + const Raul::Atom& poly = get_property(Shared::LV2URIMap::instance().ingen_polyphony); + return poly.is_valid() ? poly.get_int32() : 1; } bool PatchModel::polyphonic() const { - return (_parent) - ? (_poly > 1) && _poly == PtrCast<PatchModel>(_parent)->poly() && _poly > 1 - : (_poly > 1); + const Raul::Atom& poly = get_property(Shared::LV2URIMap::instance().ingen_polyphonic); + return poly.is_valid() && poly.get_bool(); } diff --git a/src/client/PatchModel.hpp b/src/client/PatchModel.hpp index d87c4ee8..1590aa10 100644 --- a/src/client/PatchModel.hpp +++ b/src/client/PatchModel.hpp @@ -46,10 +46,11 @@ public: SharedPtr<ConnectionModel> get_connection(const Raul::Path& src_port_path, const Raul::Path& dst_port_path) const; - uint32_t poly() const { return _poly; } - uint32_t internal_polyphony() const { return _poly; } - bool enabled() const; - bool polyphonic() const; + //uint32_t poly() const { return _poly; } + bool enabled() const; + bool polyphonic() const; + + uint32_t internal_poly() const; /** "editable" = arranging,connecting,adding,deleting,etc * not editable (control mode) you can just change controllers (performing) @@ -62,8 +63,6 @@ public: } } - virtual Raul::Atom& set_meta_property(const Raul::URI& key, const Raul::Atom& value); - // Signals sigc::signal<void, SharedPtr<NodeModel> > signal_new_node; sigc::signal<void, SharedPtr<NodeModel> > signal_removed_node; @@ -74,10 +73,9 @@ public: private: friend class ClientStore; - PatchModel(const Raul::Path& patch_path, size_t internal_poly) + PatchModel(const Raul::Path& patch_path) : NodeModel("http://drobilla.net/ns/ingen#Patch", patch_path) , _connections(new Connections()) - , _poly(internal_poly) , _editable(true) { } @@ -90,7 +88,6 @@ private: void remove_connection(const Raul::Path& src_port_path, const Raul::Path& dst_port_path); SharedPtr<Connections> _connections; - uint32_t _poly; bool _editable; }; diff --git a/src/common/interface/GraphObject.hpp b/src/common/interface/GraphObject.hpp index 91058858..d53658c5 100644 --- a/src/common/interface/GraphObject.hpp +++ b/src/common/interface/GraphObject.hpp @@ -46,7 +46,6 @@ public: virtual const Raul::Path& path() const = 0; virtual const Raul::Symbol& symbol() const = 0; - virtual bool polyphonic() const = 0; virtual GraphObject* graph_parent() const = 0; }; diff --git a/src/common/interface/Node.hpp b/src/common/interface/Node.hpp index 4a700a12..7a1a6280 100644 --- a/src/common/interface/Node.hpp +++ b/src/common/interface/Node.hpp @@ -21,6 +21,7 @@ #include <stdint.h> #include "GraphObject.hpp" +#include <iostream> namespace Ingen { namespace Shared { diff --git a/src/common/interface/Patch.hpp b/src/common/interface/Patch.hpp index ea6a0507..0817d7c2 100644 --- a/src/common/interface/Patch.hpp +++ b/src/common/interface/Patch.hpp @@ -39,8 +39,8 @@ public: virtual const Connections& connections() const = 0; - virtual bool enabled() const = 0; - virtual uint32_t internal_polyphony() const = 0; + virtual bool enabled() const = 0; + virtual uint32_t internal_poly() const = 0; }; diff --git a/src/engine/AudioBuffer.cpp b/src/engine/AudioBuffer.cpp index 90534f90..99d97e14 100644 --- a/src/engine/AudioBuffer.cpp +++ b/src/engine/AudioBuffer.cpp @@ -36,15 +36,14 @@ namespace Ingen { using namespace Shared; -AudioBuffer::AudioBuffer(BufferFactory& factory, Shared::PortType type, size_t size) - : ObjectBuffer(factory, size + sizeof(LV2_Object) - + (type == PortType::AUDIO ? sizeof(LV2_Vector_Body) : 0)) +AudioBuffer::AudioBuffer(BufferFactory& bufs, Shared::PortType type, size_t size) + : ObjectBuffer(bufs, size) , _state(OK) , _set_value(0) , _set_time(0) { - assert(size >= sizeof(Sample)); - assert(this->size() > size); + assert(size >= sizeof(LV2_Object) + sizeof(Sample)); + assert(this->size() >= size); assert(data()); _type = type; @@ -67,6 +66,8 @@ AudioBuffer::AudioBuffer(BufferFactory& factory, Shared::PortType type, size_t s << "\tdata @ " << (void*)data() << "\t(offset " << (char*)data() - (char*)object() << ")" << endl;*/ + + clear(); } @@ -111,7 +112,9 @@ AudioBuffer::set_value(Sample val, FrameTime cycle_start, FrameTime time) if (offset < nframes()) { set_block(val, offset, nframes() - 1); - if (offset > 0) + if (offset == 0) + _state = OK; + else _state = HALF_SET_CYCLE_1; } // else trigger at very end of block diff --git a/src/engine/AudioBuffer.hpp b/src/engine/AudioBuffer.hpp index b8500537..cfac3d59 100644 --- a/src/engine/AudioBuffer.hpp +++ b/src/engine/AudioBuffer.hpp @@ -32,7 +32,7 @@ namespace Ingen { class AudioBuffer : public ObjectBuffer { public: - AudioBuffer(BufferFactory& factory, Shared::PortType type, size_t capacity); + AudioBuffer(BufferFactory& bufs, Shared::PortType type, size_t capacity); void clear(); diff --git a/src/engine/Buffer.hpp b/src/engine/Buffer.hpp index 0d2574e6..b6d8b722 100644 --- a/src/engine/Buffer.hpp +++ b/src/engine/Buffer.hpp @@ -37,8 +37,8 @@ class BufferFactory; class Buffer : public boost::noncopyable, public Raul::Deletable { public: - Buffer(BufferFactory& factory, Shared::PortType type, size_t size) - : _factory(factory) + Buffer(BufferFactory& bufs, Shared::PortType type, size_t size) + : _factory(bufs) , _type(type) , _size(size) , _refs(0) diff --git a/src/engine/BufferFactory.cpp b/src/engine/BufferFactory.cpp index 39c644e2..83030c70 100644 --- a/src/engine/BufferFactory.cpp +++ b/src/engine/BufferFactory.cpp @@ -35,16 +35,39 @@ using namespace Shared; BufferFactory::BufferFactory(Engine& engine, SharedPtr<Shared::LV2URIMap> map) : _engine(engine) , _map(map) + , _silent_buffer(NULL) { } -struct BufferDeleter { - BufferDeleter(BufferFactory& bf) : _factory(bf) {} - void operator()(void* ptr) { - _factory.recycle((Buffer*)ptr); + +void +BufferFactory::set_block_length(SampleCount block_length) +{ + _silent_buffer = create(PortType::AUDIO, audio_buffer_size(block_length)); +} + + +size_t +BufferFactory::audio_buffer_size(SampleCount nframes) +{ + return sizeof(LV2_Object) + sizeof(LV2_Vector_Body) + (nframes * sizeof(float)); +} + + +size_t +BufferFactory::default_buffer_size(PortType type) +{ + switch (type.symbol()) { + case PortType::AUDIO: + return audio_buffer_size(_engine.driver()->block_length()); + case PortType::CONTROL: + return sizeof(LV2_Object) + sizeof(float); + case PortType::EVENTS: + return _engine.driver()->block_length() * event_bytes_per_frame; + default: + return 1024; // Who knows } - BufferFactory& _factory; -}; +} BufferFactory::Ref @@ -67,6 +90,7 @@ BufferFactory::get(Shared::PortType type, size_t size, bool force_create) if (ThreadManager::current_thread_id() != THREAD_PROCESS) { return create(type, size); } else { + assert(false); error << "Failed to obtain buffer" << endl; return Ref(); } @@ -84,36 +108,32 @@ BufferFactory::create(Shared::PortType type, size_t size) Buffer* buffer = NULL; + if (size == 0) + size = default_buffer_size(type); + if (type.is_control()) { - if (size == 0) - size = sizeof(LV2_Object) + sizeof(float); AudioBuffer* ret = new AudioBuffer(*this, type, size); ret->object()->type = _map->object_class_vector.id; ((LV2_Vector_Body*)ret->object()->body)->elem_type = _map->object_class_float32.id; buffer = ret; } else if (type.is_audio()) { - if (size == 0) - size = sizeof(LV2_Object) + sizeof(LV2_Vector_Body) - + _engine.driver()->buffer_size() * sizeof(float); AudioBuffer* ret = new AudioBuffer(*this, type, size); ret->object()->type = _map->object_class_float32.id; buffer = ret; } else if (type.is_events()) { - if (size == 0) - size = _engine.driver()->buffer_size() * 4; // FIXME buffer = new EventBuffer(*this, size); } else if (type.is_value() || type.is_message()) { - if (size == 0) - size = 32; // FIXME buffer = new ObjectBuffer(*this, std::max(size, sizeof(LV2_Object) + sizeof(void*))); } else { error << "Failed to create buffer of unknown type" << endl; return Ref(); } + assert(buffer); return Ref(buffer); } + void BufferFactory::recycle(Buffer* buf) { diff --git a/src/engine/BufferFactory.hpp b/src/engine/BufferFactory.hpp index 1978e895..44213c52 100644 --- a/src/engine/BufferFactory.hpp +++ b/src/engine/BufferFactory.hpp @@ -24,6 +24,7 @@ #include "glibmm/thread.h" #include "raul/RingBuffer.hpp" #include "raul/AtomicPtr.hpp" +#include "types.hpp" namespace Ingen { @@ -40,10 +41,16 @@ public: typedef boost::intrusive_ptr<Buffer> Ref; + static size_t audio_buffer_size(SampleCount nframes); + size_t default_buffer_size(PortType type); + Ref get(Shared::PortType type, size_t size=0, bool force_create=false); + Ref silent_buffer() { return _silent_buffer; } + + void set_block_length(SampleCount block_length); + private: - friend class BufferDeleter; friend class Buffer; void recycle(Buffer* buf); @@ -68,6 +75,8 @@ private: Glib::Mutex _mutex; Engine& _engine; SharedPtr<Shared::LV2URIMap> _map; + + Ref _silent_buffer; }; } // namespace Ingen diff --git a/src/engine/ConnectionImpl.cpp b/src/engine/ConnectionImpl.cpp index 3beca4c8..4a154809 100644 --- a/src/engine/ConnectionImpl.cpp +++ b/src/engine/ConnectionImpl.cpp @@ -55,11 +55,8 @@ ConnectionImpl::ConnectionImpl(BufferFactory& bufs, PortImpl* src_port, PortImpl if (must_mix() || must_queue()) _local_buffer = bufs.get(dst_port->type(), dst_port->buffer_size(), true); - if (must_queue()) _queue = new Raul::RingBuffer<LV2_Object>(src_port->buffer_size() * 2); - - //dump(); } @@ -68,24 +65,38 @@ ConnectionImpl::dump() const { debug << _src_port->path() << " -> " << _dst_port->path() << (must_mix() ? " (MIX) " : " (DIRECT) ") - << (must_queue() ? " (QUEUE)" : " (NOQUEUE)") << endl; + << (must_queue() ? " (QUEUE)" : " (NOQUEUE) ") + << "POLY: " << _src_port->poly() << " => " << _dst_port->poly() << endl; } void -ConnectionImpl::set_buffer_size(BufferFactory& bufs, size_t size) +ConnectionImpl::update_buffer_size(Context& context, BufferFactory& bufs) { - if (must_mix()) - _local_buffer = bufs.get(_dst_port->type(), _dst_port->buffer(0)->size()); + if (must_mix() || must_queue()) + allocate_buffer(bufs); +} + + +void +ConnectionImpl::allocate_buffer(BufferFactory& bufs) +{ + if (!_local_buffer) + _local_buffer = bufs.get(_dst_port->type(), _dst_port->buffer_size()); } void ConnectionImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) { - _src_port->prepare_poly(bufs, poly); + ThreadManager::assert_thread(THREAD_PRE_PROCESS); - if (must_mix()) + assert(_src_port->prepared_poly() == _dst_port->prepared_poly() + || _src_port->prepared_poly() == 1 + || _dst_port->prepared_poly() == 1); + + const bool mix = _src_port->prepared_poly() > _dst_port->prepared_poly(); + if ((mix || must_queue()) && !_local_buffer) _local_buffer = bufs.get(_dst_port->type(), _dst_port->buffer(0)->size()); } @@ -93,12 +104,15 @@ ConnectionImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) void ConnectionImpl::apply_poly(Raul::Maid& maid, uint32_t poly) { - _src_port->apply_poly(maid, poly); + ThreadManager::assert_thread(THREAD_PROCESS); + + assert(_src_port->poly() == _dst_port->poly() + || _src_port->poly() == 1 + || _dst_port->poly() == 1); // Recycle buffer if it's no longer needed - if (!must_mix() && _local_buffer) - _local_buffer.reset(NULL); - //_local_buffer.reset(); // old boost is missing this + if (!(must_mix() || must_queue())) + _local_buffer = NULL; } @@ -118,6 +132,8 @@ ConnectionImpl::process(Context& context) return; } + local_buf->clear(); + if (_queue->read_space()) { LV2_Object obj; _queue->full_peek(sizeof(LV2_Object), &obj); @@ -130,6 +146,7 @@ ConnectionImpl::process(Context& context) for (uint32_t v = 0; v < num_srcs; ++v) srcs[v] = src_port()->buffer(v).get(); + _local_buffer->clear(); mix(context, _local_buffer.get(), srcs, num_srcs); } } diff --git a/src/engine/ConnectionImpl.hpp b/src/engine/ConnectionImpl.hpp index bd115293..896b055b 100644 --- a/src/engine/ConnectionImpl.hpp +++ b/src/engine/ConnectionImpl.hpp @@ -64,6 +64,9 @@ public: void process(Context& context); void queue(Context& context); + void allocate_buffer(BufferFactory& bufs); + void recycle_buffer() { _local_buffer = NULL; } + /** Get the buffer for a particular voice. * A Connection is smart - it knows the destination port requesting the * buffer, and will return accordingly (e.g. the same buffer for every @@ -72,14 +75,14 @@ public: inline BufferFactory::Ref buffer(uint32_t voice) const { if (must_mix() || must_queue()) { return _local_buffer; - } else if ( ! _src_port->polyphonic()) { + } else if (_src_port->poly() == 1) { return _src_port->buffer(0); } else { return _src_port->buffer(voice); } } - void set_buffer_size(BufferFactory& bufs, size_t size); + void update_buffer_size(Context& context, BufferFactory& bufs); void prepare_poly(BufferFactory& bufs, uint32_t poly); void apply_poly(Raul::Maid& maid, uint32_t poly); diff --git a/src/engine/Driver.hpp b/src/engine/Driver.hpp index 53db2ab1..3712b93b 100644 --- a/src/engine/Driver.hpp +++ b/src/engine/Driver.hpp @@ -105,8 +105,8 @@ public: virtual void set_root_patch(PatchImpl* patch) = 0; virtual PatchImpl* root_patch() = 0; - /** Return the buffer size in frames (i.e. the maximum length of a process cycle) */ - virtual SampleCount buffer_size() const = 0; + /** Return the audio buffer size in frames (i.e. the maximum length of a process cycle) */ + virtual SampleCount block_length() const = 0; /** Return the sample rate in Hz */ virtual SampleCount sample_rate() const = 0; diff --git a/src/engine/DuplexPort.cpp b/src/engine/DuplexPort.cpp index 775e82b3..1e23b5b5 100644 --- a/src/engine/DuplexPort.cpp +++ b/src/engine/DuplexPort.cpp @@ -17,6 +17,7 @@ #include <cstdlib> #include <cassert> +#include "shared/LV2URIMap.hpp" #include "util.hpp" #include "DuplexPort.hpp" #include "ConnectionImpl.hpp" @@ -37,6 +38,7 @@ DuplexPort::DuplexPort( NodeImpl* parent, const string& name, uint32_t index, + bool polyphonic, uint32_t poly, PortType type, const Raul::Atom& value, @@ -48,6 +50,17 @@ DuplexPort::DuplexPort( , _is_output(is_output) { assert(PortImpl::_parent == parent); + set_property(Shared::LV2URIMap::instance().ingen_polyphonic, polyphonic); +} + + +void +DuplexPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) +{ + if (_is_output) + return InputPort::get_buffers(bufs, buffers, poly); + else + return OutputPort::get_buffers(bufs, buffers, poly); } diff --git a/src/engine/DuplexPort.hpp b/src/engine/DuplexPort.hpp index a5963908..aab33c33 100644 --- a/src/engine/DuplexPort.hpp +++ b/src/engine/DuplexPort.hpp @@ -43,6 +43,7 @@ public: NodeImpl* parent, const std::string& name, uint32_t index, + bool polyphonic, uint32_t poly, Shared::PortType type, const Raul::Atom& value, @@ -51,6 +52,8 @@ public: virtual ~DuplexPort() {} + void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); + void pre_process(Context& context); void post_process(Context& context); diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index fe9bdd8c..dde8ec8b 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -166,6 +166,8 @@ Engine::activate() { assert(_driver); + _buffer_factory->set_block_length(_driver->block_length()); + _message_context->Thread::start(); uint32_t parallelism = _world->conf->option("parallelism").get_int32(); @@ -178,12 +180,11 @@ Engine::activate() // Create root patch PatchImpl* root_patch = _driver->root_patch(); if (!root_patch) { - root_patch = new PatchImpl(*this, "root", 1, NULL, - _driver->sample_rate(), _driver->buffer_size(), 1); + root_patch = new PatchImpl(*this, "root", 1, NULL, _driver->sample_rate(), 1); root_patch->meta().set_property(uris.rdf_type, uris.ingen_Patch); root_patch->meta().set_property(uris.ingen_polyphony, Raul::Atom(int32_t(1))); root_patch->set_property(uris.rdf_type, uris.ingen_Node); - root_patch->activate(); + root_patch->activate(*_buffer_factory); _world->store->add(root_patch); root_patch->compiled_patch(root_patch->compile()); _driver->set_root_patch(root_patch); diff --git a/src/engine/EventBuffer.cpp b/src/engine/EventBuffer.cpp index e1e55fdb..2ba74937 100644 --- a/src/engine/EventBuffer.cpp +++ b/src/engine/EventBuffer.cpp @@ -34,8 +34,8 @@ using namespace Shared; /** Allocate a new event buffer. * \a capacity is in bytes (not number of events). */ -EventBuffer::EventBuffer(BufferFactory& factory, size_t capacity) - : Buffer(factory, PortType(PortType::EVENTS), capacity) +EventBuffer::EventBuffer(BufferFactory& bufs, size_t capacity) + : Buffer(bufs, PortType(PortType::EVENTS), capacity) , _latest_frames(0) , _latest_subframes(0) { diff --git a/src/engine/EventBuffer.hpp b/src/engine/EventBuffer.hpp index 3cddf6c1..2007cdf1 100644 --- a/src/engine/EventBuffer.hpp +++ b/src/engine/EventBuffer.hpp @@ -29,7 +29,7 @@ namespace Ingen { class EventBuffer : public Buffer { public: - EventBuffer(BufferFactory& factory, size_t capacity); + EventBuffer(BufferFactory& bufs, size_t capacity); ~EventBuffer(); void* port_data(Shared::PortType port_type) { return _data; } diff --git a/src/engine/GraphObjectImpl.cpp b/src/engine/GraphObjectImpl.cpp index 60aefa85..b9c8100c 100644 --- a/src/engine/GraphObjectImpl.cpp +++ b/src/engine/GraphObjectImpl.cpp @@ -28,13 +28,12 @@ namespace Ingen { using namespace Shared; -GraphObjectImpl::GraphObjectImpl(GraphObjectImpl* parent, const Symbol& symbol, bool polyphonic) +GraphObjectImpl::GraphObjectImpl(GraphObjectImpl* parent, const Symbol& symbol) : ResourceImpl(parent ? parent->path().child(symbol) : Raul::Path::root.child(symbol)) , _parent(parent) , _path(parent ? parent->path().child(symbol) : "/") , _symbol(symbol) , _meta(ResourceImpl::meta_uri(uri())) - , _polyphonic(polyphonic) { } diff --git a/src/engine/GraphObjectImpl.hpp b/src/engine/GraphObjectImpl.hpp index 82ff7f53..854fdab1 100644 --- a/src/engine/GraphObjectImpl.hpp +++ b/src/engine/GraphObjectImpl.hpp @@ -35,6 +35,7 @@ namespace Ingen { class PatchImpl; class Context; class ProcessContext; +class BufferFactory; /** An object on the audio graph - Patch, Node, Port, etc. @@ -55,15 +56,12 @@ public: const Raul::URI& uri() const { return _path; } const Raul::Symbol& symbol() const { return _symbol; } - bool polyphonic() const { return _polyphonic; } - virtual bool set_polyphonic(Raul::Maid& maid, bool p) { _polyphonic = p; return true; } - GraphObject* graph_parent() const { return _parent; } GraphObjectImpl* parent() const { return _parent; } Resource& meta() { return _meta; } const Resource& meta() const { return _meta; } - virtual void process(ProcessContext& context) = 0; + //virtual void process(ProcessContext& context) = 0; /** Rename */ virtual void set_path(const Raul::Path& new_path) { @@ -83,14 +81,29 @@ public: SharedPtr<GraphObject> find_child(const std::string& name) const; + /** Prepare for a new (external) polyphony value. + * + * Preprocessor thread, poly is actually applied by apply_poly. + * \return true on success. + */ + virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly) = 0; + + /** Apply a new (external) polyphony value. + * + * Audio thread. + * + * \param poly Must be <= the most recent value passed to prepare_poly. + * \param maid Any objects no longer needed will be pushed to this + */ + virtual bool apply_poly(Raul::Maid& maid, uint32_t poly) = 0; + protected: - GraphObjectImpl(GraphObjectImpl* parent, const Raul::Symbol& symbol, bool polyphonic=false); + GraphObjectImpl(GraphObjectImpl* parent, const Raul::Symbol& symbol); GraphObjectImpl* _parent; Raul::Path _path; Raul::Symbol _symbol; ResourceImpl _meta; - bool _polyphonic; }; diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp index 75f0234e..04573a1a 100644 --- a/src/engine/InputPort.cpp +++ b/src/engine/InputPort.cpp @@ -47,6 +47,7 @@ InputPort::InputPort(BufferFactory& bufs, const Raul::Atom& value, size_t buffer_size) : PortImpl(bufs, parent, symbol, index, poly, type, value, buffer_size) + , _num_connections(0) { const LV2URIMap& uris = Shared::LV2URIMap::instance(); @@ -62,81 +63,60 @@ InputPort::InputPort(BufferFactory& bufs, bool -InputPort::can_direct() const +InputPort::apply_poly(Maid& maid, uint32_t poly) { - return _connections.size() == 1 - && _connections.front()->src_port()->poly() == poly() - && (_connections.front()->src_port()->type() == type() - || (_connections.front()->src_port()->type() == PortType::AUDIO - && type() == PortType::CONTROL)); -} - - -void -InputPort::set_buffer_size(BufferFactory& bufs, size_t size) -{ - PortImpl::set_buffer_size(bufs, size); - assert(_buffer_size = size); + bool ret = PortImpl::apply_poly(maid, poly); + if (!ret) + poly = 1; - for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - ((ConnectionImpl*)c->get())->set_buffer_size(bufs, size); -} - - -bool -InputPort::prepare_poly(BufferFactory& bufs, uint32_t poly) -{ - PortImpl::prepare_poly(bufs, poly); - - for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - ((ConnectionImpl*)c->get())->prepare_poly(bufs, poly); + assert(_buffers->size() >= poly); return true; } -bool -InputPort::apply_poly(Raul::Maid& maid, uint32_t poly) +void +InputPort::set_buffer_size(Context& context, BufferFactory& bufs, size_t size) { - if (!_polyphonic || !_parent->polyphonic()) - return true; + PortImpl::set_buffer_size(context, bufs, size); for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) - ((ConnectionImpl*)c->get())->apply_poly(maid, poly); - - PortImpl::apply_poly(maid, poly); - assert(this->poly() == poly); - - if (_connections.size() == 1) { - ConnectionImpl* c = _connections.begin()->get(); - for (uint32_t v = _poly; v < poly; ++v) - _buffers->at(v) = c->buffer(v); - } - - for (uint32_t i = 0; i < _poly; ++i) - PortImpl::parent_node()->set_port_buffer(i, _index, buffer(i)); - - return true; + ((ConnectionImpl*)c->get())->update_buffer_size(context, bufs); } -/** Connect buffers to the appropriate locations based on the current connections */ +/** Set \a buffers appropriately if this port has \a num_connections connections. + */ void -InputPort::connect_buffers() +InputPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) { - // Single connection now, use it directly - if (_connections.size() == 1) { - for (uint32_t v = 0; v < _poly; ++v) - _buffers->at(v) = _connections.front()->buffer(v); + size_t num_connections = (ThreadManager::current_thread_id() == THREAD_PROCESS) + ? _connections.size() : _num_connections; + + if (_type == PortType::AUDIO && num_connections == 0) { + // Audio input with no connections, use shared zero buffer + for (uint32_t v = 0; v < poly; ++v) + buffers->at(v) = bufs.silent_buffer(); + + } else if (num_connections == 1) { + if (ThreadManager::current_thread_id() == THREAD_PROCESS) { + // Single connection, use it directly + for (uint32_t v = 0; v < poly; ++v) + buffers->at(v) = _connections.front()->buffer(v); + } else { + // Not in the process thread, will be set later + for (uint32_t v = 0; v < poly; ++v) + buffers->at(v) = NULL; + } - // Use local buffers } else { - for (uint32_t v = 0; v < _poly; ++v) - _buffers->at(v) = _bufs.get(_type, _buffer_size); // Use local buffer + // Use local buffers + for (uint32_t v = 0; v < poly; ++v) { + buffers->at(v) = NULL; // Release first (potential immediate recycling) + buffers->at(v) = _bufs.get(_type, _buffer_size); + buffers->at(v)->clear(); + } } - - // Connect node to buffers - PortImpl::connect_buffers(); } @@ -144,6 +124,9 @@ InputPort::connect_buffers() * * The buffer of this port will be set directly to the connection's buffer * if there is only one connection, since no copying/mixing needs to take place. + * + * Note that setup_buffers must be called after this before the change + * will audibly take effect. */ void InputPort::add_connection(Connections::Node* const c) @@ -151,7 +134,6 @@ InputPort::add_connection(Connections::Node* const c) ThreadManager::assert_thread(THREAD_PROCESS); _connections.push_back(c); - connect_buffers(); // Automatically broadcast connected control inputs if (_type == PortType::CONTROL) @@ -159,9 +141,13 @@ InputPort::add_connection(Connections::Node* const c) } -/** Remove a connection. Realtime safe. */ +/** Remove a connection. Realtime safe. + * + * Note that setup_buffers must be called after this before the change + * will audibly take effect. + */ InputPort::Connections::Node* -InputPort::remove_connection(const OutputPort* src_port) +InputPort::remove_connection(ProcessContext& context, const OutputPort* src_port) { ThreadManager::assert_thread(THREAD_PROCESS); @@ -181,12 +167,6 @@ InputPort::remove_connection(const OutputPort* src_port) return NULL; } - connect_buffers(); - - if (_connections.size() == 0) - for (uint32_t v = 0; v < _poly; ++v) - buffer(v)->clear(); - // Turn off broadcasting if we're no longer connected if (_type == PortType::CONTROL && _connections.size() == 0) _broadcast = false; @@ -204,14 +184,15 @@ InputPort::pre_process(Context& context) if (_set_by_user) return; - //connect_buffers(); - // Process connections (mix down polyphony, if necessary) for (Connections::iterator c = _connections.begin(); c != _connections.end(); ++c) (*c)->process(context); // Multiple connections, mix them all into our local buffers if (_connections.size() > 1) { + for (uint32_t v = 0; v < _poly; ++v) + buffer(v)->prepare_write(context); + for (uint32_t v = 0; v < _poly; ++v) { const uint32_t num_srcs = _connections.size(); Connections::iterator c = _connections.begin(); @@ -237,7 +218,7 @@ void InputPort::post_process(Context& context) { // Prepare buffers for next cycle - if (!can_direct()) + if (type() != PortType::CONTROL && num_connections() > 1) for (uint32_t v = 0; v < _poly; ++v) buffer(v)->prepare_write(context); @@ -245,5 +226,12 @@ InputPort::post_process(Context& context) } +bool +InputPort::is_silent() const +{ + return (_connections.size() == 0 && _type == PortType::AUDIO); +} + + } // namespace Ingen diff --git a/src/engine/InputPort.hpp b/src/engine/InputPort.hpp index 16e25cab..21cf3372 100644 --- a/src/engine/InputPort.hpp +++ b/src/engine/InputPort.hpp @@ -28,8 +28,10 @@ namespace Ingen { class ConnectionImpl; -class OutputPort; +class Context; class NodeImpl; +class OutputPort; +class ProcessContext; /** An input port on a Node or Patch. @@ -53,31 +55,33 @@ public: uint32_t poly, Shared::PortType type, const Raul::Atom& value, - size_t buffer_size); + size_t buffer_size=0); virtual ~InputPort() {} typedef Raul::List< SharedPtr<ConnectionImpl> > Connections; void add_connection(Connections::Node* c); - Connections::Node* remove_connection(const OutputPort* src_port); + Connections::Node* remove_connection(ProcessContext& context, const OutputPort* src_port); - void set_buffer_size(BufferFactory& bufs, size_t size); - bool prepare_poly(BufferFactory& bufs, uint32_t poly); bool apply_poly(Raul::Maid& maid, uint32_t poly); + void set_buffer_size(Context& context, BufferFactory& bufs, size_t size); + + void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); void pre_process(Context& context); void post_process(Context& context); - size_t num_connections() const { return _connections.size(); } + size_t num_connections() const { return _num_connections; } ///< Pre-process thread + void increment_num_connections() { ++_num_connections; } + void decrement_num_connections() { --_num_connections; } bool is_input() const { return true; } bool is_output() const { return false; } + bool is_silent() const; protected: - void connect_buffers(); - bool can_direct() const; - + size_t _num_connections; ///< Pre-process thread Connections _connections; }; diff --git a/src/engine/InternalPlugin.cpp b/src/engine/InternalPlugin.cpp index b312a24b..b4b0be8b 100644 --- a/src/engine/InternalPlugin.cpp +++ b/src/engine/InternalPlugin.cpp @@ -49,16 +49,15 @@ InternalPlugin::instantiate(BufferFactory& bufs, { assert(_type == Internal); - SampleCount srate = engine.driver()->sample_rate(); - SampleCount buffer_size = engine.driver()->buffer_size(); + const SampleCount srate = engine.driver()->sample_rate(); const string uri_str = uri().str(); if (uri_str == NS_INTERNALS "Note") { - return new NoteNode(bufs, name, polyphonic, parent, srate, buffer_size); + return new NoteNode(bufs, name, polyphonic, parent, srate); } else if (uri_str == NS_INTERNALS "Trigger") { - return new TriggerNode(bufs, name, polyphonic, parent, srate, buffer_size); + return new TriggerNode(bufs, name, polyphonic, parent, srate); } else if (uri_str == NS_INTERNALS "Controller") { - return new ControllerNode(bufs, name, polyphonic, parent, srate, buffer_size); + return new ControllerNode(bufs, name, polyphonic, parent, srate); } else { return NULL; } diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index e903586e..18426bf4 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -60,11 +60,8 @@ JackPort::JackPort(JackDriver* driver, DuplexPort* patch_port) , _driver(driver) , _jack_port(NULL) { - assert(patch_port->poly() == 1); - + patch_port->setup_buffers(*driver->_engine.buffer_factory(), patch_port->poly()); create(); - - patch_port->buffer(0)->clear(); } @@ -188,7 +185,7 @@ JackDriver::JackDriver(Engine& engine) , _sem(0) , _flag(0) , _client(NULL) - , _buffer_size(0) + , _block_length(0) , _sample_rate(0) , _is_activated(false) , _local_client(true) @@ -252,14 +249,14 @@ JackDriver::attach(const std::string& server_name, _local_client = (jack_client == NULL); - _buffer_size = jack_get_buffer_size(_client) * sizeof(Sample); + _block_length = jack_get_buffer_size(_client); _sample_rate = jack_get_sample_rate(_client); jack_on_shutdown(_client, shutdown_cb, this); jack_set_thread_init_callback(_client, thread_init_cb, this); jack_set_sample_rate_callback(_client, sample_rate_cb, this); - jack_set_buffer_size_callback(_client, buffer_size_cb, this); + jack_set_buffer_size_callback(_client, block_length_cb, this); for (Raul::List<JackPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i) (*i)->create(); @@ -370,7 +367,7 @@ DriverPort* JackDriver::create_port(DuplexPort* patch_port) { try { - if (patch_port->buffer_size() == _buffer_size) + if (patch_port->type() == PortType::AUDIO || patch_port->type() == PortType::EVENTS) return new JackPort(this, patch_port); else return NULL; @@ -412,7 +409,7 @@ JackDriver::_process_cb(jack_nframes_t nframes) // FIXME: all of this time stuff is screwy // FIXME: support nframes != buffer_size, even though that never damn well happens - assert(nframes == _buffer_size / sizeof(Sample)); + assert(nframes == _block_length); // Note that Jack can not call this function for a cycle, if overloaded const jack_nframes_t start_of_current_cycle = jack_last_frame_time(_client); @@ -497,11 +494,12 @@ JackDriver::_sample_rate_cb(jack_nframes_t nframes) int -JackDriver::_buffer_size_cb(jack_nframes_t nframes) +JackDriver::_block_length_cb(jack_nframes_t nframes) { if (_root_patch) { - _buffer_size = nframes * sizeof(Sample); - _root_patch->set_buffer_size(*_engine.buffer_factory(), _buffer_size); + _block_length = nframes; + _root_patch->set_buffer_size(context(), *_engine.buffer_factory(), PortType::AUDIO, + _engine.buffer_factory()->audio_buffer_size(nframes)); } return 0; } diff --git a/src/engine/JackDriver.hpp b/src/engine/JackDriver.hpp index 6f63ff92..e2450d06 100644 --- a/src/engine/JackDriver.hpp +++ b/src/engine/JackDriver.hpp @@ -112,7 +112,7 @@ public: bool is_realtime() const { return jack_is_realtime(_client); } jack_client_t* jack_client() const { return _client; } - SampleCount buffer_size() const { return _buffer_size; } + SampleCount block_length() const { return _block_length; } SampleCount sample_rate() const { return _sample_rate; } bool is_activated() const { return _is_activated; } @@ -133,8 +133,8 @@ private: inline static int process_cb(jack_nframes_t nframes, void* const jack_driver) { return ((JackDriver*)jack_driver)->_process_cb(nframes); } - inline static int buffer_size_cb(jack_nframes_t nframes, void* const jack_driver) { - return ((JackDriver*)jack_driver)->_buffer_size_cb(nframes); + inline static int block_length_cb(jack_nframes_t nframes, void* const jack_driver) { + return ((JackDriver*)jack_driver)->_block_length_cb(nframes); } inline static int sample_rate_cb(jack_nframes_t nframes, void* const jack_driver) { return ((JackDriver*)jack_driver)->_sample_rate_cb(nframes); @@ -144,7 +144,7 @@ private: void _thread_init_cb(); void _shutdown_cb(); int _process_cb(jack_nframes_t nframes); - int _buffer_size_cb(jack_nframes_t nframes); + int _block_length_cb(jack_nframes_t nframes); int _sample_rate_cb(jack_nframes_t nframes); Engine& _engine; @@ -152,7 +152,7 @@ private: Raul::Semaphore _sem; Raul::AtomicInt _flag; jack_client_t* _client; - jack_nframes_t _buffer_size; + jack_nframes_t _block_length; jack_nframes_t _sample_rate; uint32_t _midi_event_type; bool _is_activated; diff --git a/src/engine/LADSPANode.cpp b/src/engine/LADSPANode.cpp index 07920b90..abc517fa 100644 --- a/src/engine/LADSPANode.cpp +++ b/src/engine/LADSPANode.cpp @@ -48,9 +48,8 @@ LADSPANode::LADSPANode(PluginImpl* plugin, bool polyphonic, PatchImpl* parent, const LADSPA_Descriptor* descriptor, - SampleRate srate, - size_t buffer_size) - : NodeBase(plugin, path, polyphonic, parent, srate, buffer_size) + SampleRate srate) + : NodeBase(plugin, path, polyphonic, parent, srate) , _descriptor(descriptor) , _instances(NULL) , _prepared_instances(NULL) @@ -62,7 +61,7 @@ LADSPANode::LADSPANode(PluginImpl* plugin, LADSPANode::~LADSPANode() { if (_instances) - for (uint32_t i=0; i < _polyphony; ++i) + for (uint32_t i = 0; i < _polyphony; ++i) _descriptor->cleanup((*_instances)[i]); delete _instances; @@ -72,6 +71,9 @@ LADSPANode::~LADSPANode() bool LADSPANode::prepare_poly(BufferFactory& bufs, uint32_t poly) { + if (!_polyphonic) + poly = 1; + NodeBase::prepare_poly(bufs, poly); if ( (!_polyphonic) @@ -79,7 +81,7 @@ LADSPANode::prepare_poly(BufferFactory& bufs, uint32_t poly) return true; } - _prepared_instances = new Raul::Array<LADSPA_Handle>(poly, *_instances); + _prepared_instances = new Raul::Array<LADSPA_Handle>(poly, *_instances, NULL); for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) { _prepared_instances->at(i) = _descriptor->instantiate(_descriptor, _srate); if (_prepared_instances->at(i) == NULL) { @@ -91,12 +93,12 @@ LADSPANode::prepare_poly(BufferFactory& bufs, uint32_t poly) for (uint32_t j = 0; j < num_ports(); ++j) { PortImpl* const port = _ports->at(j); Buffer* const buffer = port->prepared_buffer(i).get(); - - // FIXME: Preserve individual voice values - if (port->type() == PortType::CONTROL) { - ((AudioBuffer*)buffer)->set_value(port->value().get_float(), 0, 0); - } else if (port->type() == PortType::AUDIO) { - ((AudioBuffer*)buffer)->set_value(0.0f, 0, 0); + if (buffer) { + if (port->type() == PortType::CONTROL) { + ((AudioBuffer*)buffer)->set_value(port->value().get_float(), 0, 0); + } else if (port->type() == PortType::AUDIO) { + ((AudioBuffer*)buffer)->set_value(0.0f, 0, 0); + } } } @@ -112,17 +114,14 @@ bool LADSPANode::apply_poly(Raul::Maid& maid, uint32_t poly) { if (!_polyphonic) - return true; + poly = 1; if (_prepared_instances) { - assert(poly <= _prepared_instances->size()); maid.push(_instances); _instances = _prepared_instances; _prepared_instances = NULL; } - assert(poly <= _instances->size()); - _polyphony = poly; return NodeBase::apply_poly(maid, poly); } @@ -145,9 +144,7 @@ LADSPANode::instantiate(BufferFactory& bufs) _instances = new Raul::Array<LADSPA_Handle>(_polyphony, NULL); - size_t port_buffer_size = 0; - - for (uint32_t i=0; i < _polyphony; ++i) { + for (uint32_t i = 0; i < _polyphony; ++i) { (*_instances)[i] = _descriptor->instantiate(_descriptor, _srate); if ((*_instances)[i] == NULL) { error << "Failed to instantiate plugin" << endl; @@ -189,11 +186,9 @@ LADSPANode::instantiate(BufferFactory& bufs) Path port_path(path().child(symbol)); PortType type = PortType::AUDIO; - port_buffer_size = _buffer_size * sizeof(Sample); if (LADSPA_IS_PORT_CONTROL(_descriptor->PortDescriptors[j])) { type = PortType::CONTROL; - port_buffer_size = sizeof(Sample); } else { assert(LADSPA_IS_PORT_AUDIO(_descriptor->PortDescriptors[j])); } @@ -206,10 +201,10 @@ LADSPANode::instantiate(BufferFactory& bufs) const float value = default_val ? default_val.get() : 0.0f; if (LADSPA_IS_PORT_INPUT(_descriptor->PortDescriptors[j])) { - port = new InputPort(bufs, this, symbol, j, _polyphony, type, value, port_buffer_size); + port = new InputPort(bufs, this, symbol, j, _polyphony, type, value); _ports->at(j) = port; } else if (LADSPA_IS_PORT_OUTPUT(_descriptor->PortDescriptors[j])) { - port = new OutputPort(bufs, this, symbol, j, _polyphony, type, value, port_buffer_size); + port = new OutputPort(bufs, this, symbol, j, _polyphony, type, value); _ports->at(j) = port; } @@ -232,12 +227,10 @@ LADSPANode::instantiate(BufferFactory& bufs) } // Set initial/default value - if (port->buffer_size() == 1) { - for (uint32_t i=0; i < _polyphony; ++i) - ((AudioBuffer*)port->buffer(i).get())->set_value(value, 0, 0); - } + if (type == PortType::CONTROL) + port->set_value(value); - if (port->is_input() && port->buffer_size() == 1) { + if (port->is_input() && type == PortType::CONTROL) { if (min) port->set_meta_property(uris.lv2_minimum, min.get()); if (max) @@ -252,25 +245,13 @@ LADSPANode::instantiate(BufferFactory& bufs) void -LADSPANode::activate() +LADSPANode::activate(BufferFactory& bufs) { - NodeBase::activate(); + NodeBase::activate(bufs); - for (uint32_t i=0; i < _polyphony; ++i) { - for (unsigned long j=0; j < num_ports(); ++j) { - PortImpl* const port = _ports->at(j); - - set_port_buffer(i, j, port->buffer(i)); - - if (port->type() == PortType::CONTROL) { - ((AudioBuffer*)port->buffer(i).get())->set_value(port->value().get_float(), 0, 0); - } else if (port->type() == PortType::AUDIO) { - ((AudioBuffer*)port->buffer(i).get())->set_value(0.0f, 0, 0); - } - } - if (_descriptor->activate != NULL) + if (_descriptor->activate != NULL) + for (uint32_t i = 0; i < _polyphony; ++i) _descriptor->activate((*_instances)[i]); - } } @@ -279,7 +260,7 @@ LADSPANode::deactivate() { NodeBase::deactivate(); - for (uint32_t i=0; i < _polyphony; ++i) + for (uint32_t i = 0; i < _polyphony; ++i) if (_descriptor->deactivate != NULL) _descriptor->deactivate((*_instances)[i]); } @@ -290,7 +271,7 @@ LADSPANode::process(ProcessContext& context) { NodeBase::pre_process(context); - for (uint32_t i=0; i < _polyphony; ++i) + for (uint32_t i = 0; i < _polyphony; ++i) _descriptor->run((*_instances)[i], context.nframes()); NodeBase::post_process(context); @@ -300,9 +281,10 @@ LADSPANode::process(ProcessContext& context) void LADSPANode::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf) { - assert(voice < _polyphony); + NodeBase::set_port_buffer(voice, port_num, buf); + _descriptor->connect_port((*_instances)[voice], port_num, - (LADSPA_Data*)buf->port_data(_ports->at(port_num)->type())); + buf ? (LADSPA_Data*)buf->port_data(_ports->at(port_num)->type()) : NULL); } diff --git a/src/engine/LADSPANode.hpp b/src/engine/LADSPANode.hpp index 6585b2ad..91293699 100644 --- a/src/engine/LADSPANode.hpp +++ b/src/engine/LADSPANode.hpp @@ -41,8 +41,7 @@ public: bool polyphonic, PatchImpl* parent, const LADSPA_Descriptor* descriptor, - SampleRate srate, - size_t buffer_size); + SampleRate srate); ~LADSPANode(); @@ -51,7 +50,7 @@ public: bool prepare_poly(BufferFactory& bufs, uint32_t poly); bool apply_poly(Raul::Maid& maid, uint32_t poly); - void activate(); + void activate(BufferFactory& bufs); void deactivate(); void process(ProcessContext& context); diff --git a/src/engine/LADSPAPlugin.cpp b/src/engine/LADSPAPlugin.cpp index 9d8c3b63..94ff36d2 100644 --- a/src/engine/LADSPAPlugin.cpp +++ b/src/engine/LADSPAPlugin.cpp @@ -67,8 +67,7 @@ LADSPAPlugin::instantiate(BufferFactory& bufs, { assert(_id != 0); - SampleCount srate = engine.driver()->sample_rate(); - SampleCount buffer_size = engine.driver()->buffer_size(); + const SampleCount srate = engine.driver()->sample_rate(); union { void* dp; @@ -97,7 +96,7 @@ LADSPAPlugin::instantiate(BufferFactory& bufs, } if (descriptor != NULL) { - n = new LADSPANode(this, name, polyphonic, parent, descriptor, srate, buffer_size); + n = new LADSPANode(this, name, polyphonic, parent, descriptor, srate); if ( ! n->instantiate(bufs) ) { delete n; diff --git a/src/engine/LV2Node.cpp b/src/engine/LV2Node.cpp index 7a8d396e..9f3995ca 100644 --- a/src/engine/LV2Node.cpp +++ b/src/engine/LV2Node.cpp @@ -47,9 +47,8 @@ LV2Node::LV2Node(LV2Plugin* plugin, const string& name, bool polyphonic, PatchImpl* parent, - SampleRate srate, - size_t buffer_size) - : NodeBase(plugin, name, polyphonic, parent, srate, buffer_size) + SampleRate srate) + : NodeBase(plugin, name, polyphonic, parent, srate) , _lv2_plugin(plugin) , _instances(NULL) , _prepared_instances(NULL) @@ -62,7 +61,7 @@ LV2Node::LV2Node(LV2Plugin* plugin, LV2Node::~LV2Node() { if (_instances) - for (uint32_t i=0; i < _polyphony; ++i) + for (uint32_t i = 0; i < _polyphony; ++i) slv2_instance_free((*_instances)[i]); delete _instances; @@ -72,6 +71,9 @@ LV2Node::~LV2Node() bool LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly) { + if (!_polyphonic) + poly = 1; + NodeBase::prepare_poly(bufs, poly); if ( (!_polyphonic) @@ -80,7 +82,7 @@ LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly) } SharedPtr<LV2Info> info = _lv2_plugin->lv2_info(); - _prepared_instances = new Raul::Array<SLV2Instance>(poly, *_instances); + _prepared_instances = new Raul::Array<SLV2Instance>(poly, *_instances, NULL); for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) { _prepared_instances->at(i) = slv2_plugin_instantiate( _lv2_plugin->slv2_plugin(), _srate, _features->array()); @@ -94,12 +96,12 @@ LV2Node::prepare_poly(BufferFactory& bufs, uint32_t poly) for (uint32_t j = 0; j < num_ports(); ++j) { PortImpl* const port = _ports->at(j); Buffer* const buffer = port->prepared_buffer(i).get(); - - // FIXME: Preserve individual voice values - if (port->type() == PortType::CONTROL) { - ((AudioBuffer*)buffer)->set_value(port->value().get_float(), 0, 0); - } else if (port->type() == PortType::AUDIO) { - ((AudioBuffer*)buffer)->set_value(0.0f, 0, 0); + if (buffer) { + if (port->type() == PortType::CONTROL) { + ((AudioBuffer*)buffer)->set_value(port->value().get_float(), 0, 0); + } else if (port->type() == PortType::AUDIO) { + ((AudioBuffer*)buffer)->set_value(0.0f, 0, 0); + } } } @@ -115,17 +117,14 @@ bool LV2Node::apply_poly(Raul::Maid& maid, uint32_t poly) { if (!_polyphonic) - return true; + poly = 1; if (_prepared_instances) { - assert(poly <= _prepared_instances->size()); maid.push(_instances); _instances = _prepared_instances; _prepared_instances = NULL; } - assert(poly <= _instances->size()); - _polyphony = poly; return NodeBase::apply_poly(maid, poly); } @@ -157,7 +156,7 @@ LV2Node::instantiate(BufferFactory& bufs) uint32_t port_buffer_size = 0; SLV2Value ctx_ext_uri = slv2_value_new_uri(info->lv2_world(), LV2_CONTEXT_MESSAGE); - for (uint32_t i=0; i < _polyphony; ++i) { + for (uint32_t i = 0; i < _polyphony; ++i) { (*_instances)[i] = slv2_plugin_instantiate(plug, _srate, _features->array()); if ((*_instances)[i] == NULL) { error << "Failed to instantiate plugin" << endl; @@ -218,22 +217,19 @@ LV2Node::instantiate(BufferFactory& bufs) PortType data_type = PortType::UNKNOWN; if (slv2_port_is_a(plug, id, info->control_class)) { data_type = PortType::CONTROL; - port_buffer_size = sizeof(Sample); } else if (slv2_port_is_a(plug, id, info->audio_class)) { data_type = PortType::AUDIO; - port_buffer_size = _buffer_size; } else if (slv2_port_is_a(plug, id, info->event_class)) { data_type = PortType::EVENTS; - port_buffer_size = _buffer_size; } else if (slv2_port_is_a(plug, id, info->value_port_class)) { data_type = PortType::VALUE; } else if (slv2_port_is_a(plug, id, info->message_port_class)) { data_type = PortType::MESSAGE; } - if (data_type == PortType::VALUE || data_type == PortType::MESSAGE) { - port_buffer_size = 0; + port_buffer_size = bufs.default_buffer_size(data_type); + if (data_type == PortType::VALUE || data_type == PortType::MESSAGE) { // Get default value, and its length SLV2Values defaults = slv2_port_get_value(plug, id, default_pred); for (uint32_t i = 0; i < slv2_values_size(defaults); ++i) { @@ -241,10 +237,8 @@ LV2Node::instantiate(BufferFactory& bufs) if (slv2_value_is_string(d)) { const char* str_val = slv2_value_as_string(d); const size_t str_val_len = strlen(str_val); - if (str_val_len >= port_buffer_size) { - val = str_val; - port_buffer_size = str_val_len; - } + val = str_val; + port_buffer_size = str_val_len; } } @@ -254,8 +248,7 @@ LV2Node::instantiate(BufferFactory& bufs) SLV2Value d = slv2_values_get_at(sizes, i); if (slv2_value_is_int(d)) { size_t size_val = slv2_value_as_int(d); - if (size_val > port_buffer_size) - port_buffer_size = size_val; + port_buffer_size = size_val; } } } @@ -280,12 +273,12 @@ LV2Node::instantiate(BufferFactory& bufs) val = isnan(def_values[j]) ? 0.0f : def_values[j]; if (direction == INPUT) - port = new InputPort(bufs, this, port_name, j, _polyphony, data_type, val, port_buffer_size); + port = new InputPort(bufs, this, port_name, j, _polyphony, data_type, val); else - port = new OutputPort(bufs, this, port_name, j, _polyphony, data_type, val, port_buffer_size); + port = new OutputPort(bufs, this, port_name, j, _polyphony, data_type, val); if (direction == INPUT && data_type == PortType::CONTROL) { - ((AudioBuffer*)port->buffer(0).get())->set_value(val.get_float(), 0, 0); + port->set_value(val); if (!isnan(min_values[j])) { port->meta().set_property(uris.lv2_minimum, min_values[j]); port->set_property(uris.lv2_minimum, min_values[j]); @@ -340,24 +333,12 @@ done: void -LV2Node::activate() +LV2Node::activate(BufferFactory& bufs) { - NodeBase::activate(); - - for (uint32_t i=0; i < _polyphony; ++i) { - for (unsigned long j=0; j < num_ports(); ++j) { - PortImpl* const port = _ports->at(j); - - set_port_buffer(i, j, port->buffer(i)); + NodeBase::activate(bufs); - if (port->type() == PortType::CONTROL) { - ((AudioBuffer*)port->buffer(i).get())->set_value(port->value().get_float(), 0, 0); - } else if (port->type() == PortType::AUDIO) { - ((AudioBuffer*)port->buffer(i).get())->set_value(0.0f, 0, 0); - } - } + for (uint32_t i = 0; i < _polyphony; ++i) slv2_instance_activate((*_instances)[i]); - } } @@ -366,7 +347,7 @@ LV2Node::deactivate() { NodeBase::deactivate(); - for (uint32_t i=0; i < _polyphony; ++i) + for (uint32_t i = 0; i < _polyphony; ++i) slv2_instance_deactivate((*_instances)[i]); } @@ -392,7 +373,7 @@ LV2Node::process(ProcessContext& context) { NodeBase::pre_process(context); - for (uint32_t i=0; i < _polyphony; ++i) + for (uint32_t i = 0; i < _polyphony; ++i) slv2_instance_run((*_instances)[i], context.nframes()); NodeBase::post_process(context); @@ -402,9 +383,9 @@ LV2Node::process(ProcessContext& context) void LV2Node::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf) { - assert(voice < _polyphony); + NodeBase::set_port_buffer(voice, port_num, buf); slv2_instance_connect_port((*_instances)[voice], port_num, - buf->port_data(_ports->at(port_num)->type())); + buf ? buf->port_data(_ports->at(port_num)->type()) : NULL); } diff --git a/src/engine/LV2Node.hpp b/src/engine/LV2Node.hpp index 3bc37dc5..57ad7998 100644 --- a/src/engine/LV2Node.hpp +++ b/src/engine/LV2Node.hpp @@ -42,8 +42,7 @@ public: const std::string& name, bool polyphonic, PatchImpl* parent, - SampleRate srate, - size_t buffer_size); + SampleRate srate); ~LV2Node(); @@ -52,7 +51,7 @@ public: bool prepare_poly(BufferFactory& bufs, uint32_t poly); bool apply_poly(Raul::Maid& maid, uint32_t poly); - void activate(); + void activate(BufferFactory& bufs); void deactivate(); void message_run(MessageContext& context); diff --git a/src/engine/LV2Plugin.cpp b/src/engine/LV2Plugin.cpp index d522307a..76c2290d 100644 --- a/src/engine/LV2Plugin.cpp +++ b/src/engine/LV2Plugin.cpp @@ -69,13 +69,12 @@ LV2Plugin::instantiate(BufferFactory& bufs, Ingen::PatchImpl* parent, Engine& engine) { - SampleCount srate = engine.driver()->sample_rate(); - SampleCount buffer_size = engine.driver()->buffer_size(); + const SampleCount srate = engine.driver()->sample_rate(); load(); // FIXME: unload at some point Glib::Mutex::Lock lock(engine.world()->rdf_world->mutex()); - LV2Node* n = new LV2Node(this, name, polyphonic, parent, srate, buffer_size); + LV2Node* n = new LV2Node(this, name, polyphonic, parent, srate); if ( ! n->instantiate(bufs) ) { delete n; diff --git a/src/engine/LV2ResizeFeature.hpp b/src/engine/LV2ResizeFeature.hpp index d65ea260..9d8d57b2 100644 --- a/src/engine/LV2ResizeFeature.hpp +++ b/src/engine/LV2ResizeFeature.hpp @@ -40,6 +40,7 @@ struct ResizeFeature : public Shared::LV2Features::Feature { port->connect_buffers(); return true; } else { + // TODO: Implement realtime allocator and support this in audio thread return false; } } diff --git a/src/engine/NodeBase.cpp b/src/engine/NodeBase.cpp index 7d07fe5a..3881ebe0 100644 --- a/src/engine/NodeBase.cpp +++ b/src/engine/NodeBase.cpp @@ -21,11 +21,12 @@ #include "raul/List.hpp" #include "raul/Array.hpp" #include "util.hpp" -#include "PluginImpl.hpp" +#include "AudioBuffer.hpp" #include "ClientBroadcaster.hpp" -#include "PortImpl.hpp" -#include "PatchImpl.hpp" #include "EngineStore.hpp" +#include "PatchImpl.hpp" +#include "PluginImpl.hpp" +#include "PortImpl.hpp" #include "ThreadManager.hpp" using namespace std; @@ -33,12 +34,12 @@ using namespace std; namespace Ingen { -NodeBase::NodeBase(PluginImpl* plugin, const Raul::Symbol& symbol, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) - : NodeImpl(parent, symbol, polyphonic) +NodeBase::NodeBase(PluginImpl* plugin, const Raul::Symbol& symbol, bool polyphonic, PatchImpl* parent, SampleRate srate) + : NodeImpl(parent, symbol) , _plugin(plugin) - , _polyphony((polyphonic && parent) ? parent->internal_polyphony() : 1) + , _polyphonic(polyphonic) + , _polyphony((polyphonic && parent) ? parent->internal_poly() : 1) , _srate(srate) - , _buffer_size(buffer_size) , _valid_ports(NULL) , _input_ready(1) , _process_lock(0) @@ -51,7 +52,7 @@ NodeBase::NodeBase(PluginImpl* plugin, const Raul::Symbol& symbol, bool polyphon { assert(_plugin); assert(_polyphony > 0); - assert(_parent == NULL || (_polyphony == parent->internal_polyphony() || _polyphony == 1)); + assert(_parent == NULL || (_polyphony == parent->internal_poly() || _polyphony == 1)); } @@ -83,21 +84,40 @@ NodeBase::plugin() const void -NodeBase::activate() +NodeBase::activate(BufferFactory& bufs) { ThreadManager::assert_thread(THREAD_PRE_PROCESS); assert(!_activated); _activated = true; + + for (unsigned long p = 0; p < num_ports(); ++p) { + PortImpl* const port = _ports->at(p); + port->setup_buffers(bufs, port->poly()); + port->connect_buffers(); + for (uint32_t v = 0; v < _polyphony; ++v) { + if (!port->buffer(v)) + continue; + if (port->type() == PortType::CONTROL) + ((AudioBuffer*)port->buffer(v).get())->set_value(port->value().get_float(), 0, 0); + else + port->buffer(v)->clear(); + } + } } void NodeBase::deactivate() { - // FIXME: Not true with monolithic GUI/engine - //ThreadManager::assert_thread(THREAD_POST_PROCESS); assert(_activated); _activated = false; + for (uint32_t i = 0; i < _polyphony; ++i) { + for (unsigned long j = 0; j < num_ports(); ++j) { + PortImpl* const port = _ports->at(j); + if (port->is_output() && port->buffer(i)) + port->buffer(i)->clear(); + } + } } @@ -107,11 +127,10 @@ NodeBase::prepare_poly(BufferFactory& bufs, uint32_t poly) ThreadManager::assert_thread(THREAD_PRE_PROCESS); if (!_polyphonic) - return true; + poly = 1; - if (_ports) - for (size_t i = 0; i < _ports->size(); ++i) - _ports->at(i)->prepare_poly(bufs, poly); + for (size_t i = 0; i < _ports->size(); ++i) + _ports->at(i)->prepare_poly(bufs, poly); return true; } @@ -123,31 +142,24 @@ NodeBase::apply_poly(Raul::Maid& maid, uint32_t poly) ThreadManager::assert_thread(THREAD_PROCESS); if (!_polyphonic) - return true; + poly = 1; - for (size_t i=0; i < num_ports(); ++i) { - _ports->at(i)->apply_poly(maid, poly); - assert(_ports->at(i)->poly() == poly); - } + _polyphony = poly; - for (uint32_t i=0; i < num_ports(); ++i) - for (uint32_t j=0; j < _polyphony; ++j) - set_port_buffer(j, i, _ports->at(i)->prepared_buffer(j)); + for (size_t i = 0; i < num_ports(); ++i) + _ports->at(i)->apply_poly(maid, poly); return true; } void -NodeBase::set_buffer_size(BufferFactory& bufs, size_t size) +NodeBase::set_buffer_size(Context& context, BufferFactory& bufs, PortType type, size_t size) { - ThreadManager::assert_thread(THREAD_PROCESS); - - _buffer_size = size; - if (_ports) - for (size_t i=0; i < _ports->size(); ++i) - _ports->at(i)->set_buffer_size(bufs, size); + for (size_t i = 0; i < _ports->size(); ++i) + if (_ports->at(i)->type() == type && _ports->at(i)->context() == context.id()) + _ports->at(i)->set_buffer_size(context, bufs, size); } @@ -253,5 +265,14 @@ NodeBase::reset_valid_ports() } +void +NodeBase::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf) +{ + /*debug << path() << " set port " << port_num << " voice " << voice + << " buffer " << buf << endl;*/ + assert(voice < _polyphony); +} + + } // namespace Ingen diff --git a/src/engine/NodeBase.hpp b/src/engine/NodeBase.hpp index 637c8560..4b5e5a19 100644 --- a/src/engine/NodeBase.hpp +++ b/src/engine/NodeBase.hpp @@ -28,13 +28,16 @@ #include "raul/Semaphore.hpp" #include "contexts.lv2/contexts.h" #include "interface/Port.hpp" +#include "interface/PortType.hpp" #include "NodeImpl.hpp" namespace Ingen { -class PluginImpl; -class PatchImpl; +class Context; class EngineStore; +class PatchImpl; +class PluginImpl; +class BufferFactory; namespace Shared { class ClientInterface; } @@ -50,15 +53,22 @@ public: const Raul::Symbol& symbol, bool poly, PatchImpl* parent, - SampleRate rate, - size_t buffer_size); + SampleRate rate); virtual ~NodeBase(); - virtual void activate(); + virtual void activate(BufferFactory& bufs); virtual void deactivate(); bool activated() { return _activated; } + /** Flag node as polyphonic. + * + * Note this will not actually allocate voices etc., prepare_poly + * and apply_poly must be called after this function to truly make + * a node polyphonic. + */ + virtual void set_polyphonic(bool p) { _polyphonic = p; } + virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly); virtual bool apply_poly(Raul::Maid& maid, uint32_t poly); @@ -81,12 +91,12 @@ public: virtual void process(ProcessContext& context) = 0; virtual void post_process(Context& context); - virtual void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf) {} + virtual void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf); - virtual void set_buffer_size(BufferFactory& bufs, size_t size); + virtual void set_buffer_size(Context& context, BufferFactory& bufs, + Shared::PortType type, size_t size); SampleRate sample_rate() const { return _srate; } - size_t buffer_size() const { return _buffer_size; } uint32_t num_ports() const { return _ports ? _ports->size() : 0; } uint32_t polyphony() const { return _polyphony; } bool traversed() const { return _traversed; } @@ -117,9 +127,9 @@ protected: PluginImpl* _plugin; + bool _polyphonic; uint32_t _polyphony; SampleRate _srate; - size_t _buffer_size; void* _valid_ports; ///< Valid port flags for message context diff --git a/src/engine/NodeImpl.hpp b/src/engine/NodeImpl.hpp index ef7c3400..05b51b83 100644 --- a/src/engine/NodeImpl.hpp +++ b/src/engine/NodeImpl.hpp @@ -31,6 +31,7 @@ namespace Shared { class Plugin; class Node; class Port; } class Buffer; class BufferFactory; +class Context; class MessageContext; class PatchImpl; class PluginImpl; @@ -52,8 +53,8 @@ class ProcessContext; class NodeImpl : public GraphObjectImpl, virtual public Ingen::Shared::Node { public: - NodeImpl(GraphObjectImpl* parent, const Raul::Symbol& symbol, bool poly) - : GraphObjectImpl(parent, symbol, poly) + NodeImpl(GraphObjectImpl* parent, const Raul::Symbol& symbol) + : GraphObjectImpl(parent, symbol) {} /** Activate this Node. @@ -62,25 +63,9 @@ public: * inserted in to a patch. Any non-realtime actions that need to be * done before the Node is ready for use should be done here. */ - virtual void activate() = 0; - virtual void deactivate() = 0; - virtual bool activated() = 0; - - /** Prepare for a new (external) polyphony value. - * - * Preprocessor thread, poly is actually applied by apply_poly. - * \return true on success. - */ - virtual bool prepare_poly(BufferFactory& bufs, uint32_t poly) = 0; - - /** Apply a new (external) polyphony value. - * - * Audio thread. - * - * \param poly Must be < the most recent value passed to prepare_poly. - * \param maid Any objects no longer needed will be pushed to this - */ - virtual bool apply_poly(Raul::Maid& maid, uint32_t poly) = 0; + virtual void activate(BufferFactory& bufs) = 0; + virtual void deactivate() = 0; + virtual bool activated() = 0; /** Parallelism: Reset flags for start of a new cycle. */ @@ -169,7 +154,8 @@ public: */ virtual const Shared::Plugin* plugin() const = 0; - virtual void set_buffer_size(BufferFactory& bufs, size_t size) = 0; + virtual void set_buffer_size(Context& context, BufferFactory& bufs, + Shared::PortType type, size_t size) = 0; }; diff --git a/src/engine/ObjectBuffer.cpp b/src/engine/ObjectBuffer.cpp index 92138ca0..e568f541 100644 --- a/src/engine/ObjectBuffer.cpp +++ b/src/engine/ObjectBuffer.cpp @@ -38,8 +38,8 @@ using namespace Shared; /** Allocate a new object buffer. * \a capacity is in bytes, including LV2_Object header */ -ObjectBuffer::ObjectBuffer(BufferFactory& factory, size_t capacity) - : Buffer(factory, PortType(PortType::VALUE), capacity) +ObjectBuffer::ObjectBuffer(BufferFactory& bufs, size_t capacity) + : Buffer(bufs, PortType(PortType::VALUE), capacity) { capacity += sizeof(LV2_Object); diff --git a/src/engine/ObjectBuffer.hpp b/src/engine/ObjectBuffer.hpp index 85afa1cb..30b1029c 100644 --- a/src/engine/ObjectBuffer.hpp +++ b/src/engine/ObjectBuffer.hpp @@ -29,7 +29,7 @@ class Context; class ObjectBuffer : public Buffer { public: - ObjectBuffer(BufferFactory& factory, size_t capacity); + ObjectBuffer(BufferFactory& bufs, size_t capacity); void clear(); diff --git a/src/engine/ObjectSender.cpp b/src/engine/ObjectSender.cpp index 2eadf1e9..7cfa5f85 100644 --- a/src/engine/ObjectSender.cpp +++ b/src/engine/ObjectSender.cpp @@ -140,9 +140,6 @@ ObjectSender::send_port(ClientInterface* client, const PortImpl* port, bool bund client->put(port->path(), port->properties()); - if (graph_parent && graph_parent->internal_polyphony() > 1) - client->set_property(port->meta_uri(), map.ingen_polyphonic, bool(port->polyphonic())); - // Send control value if (port->type() == PortType::CONTROL) { //const Sample& value = PtrCast<const AudioBuffer>(port->buffer(0))->value_at(0); diff --git a/src/engine/OutputPort.cpp b/src/engine/OutputPort.cpp index c6ad3356..269d6da6 100644 --- a/src/engine/OutputPort.cpp +++ b/src/engine/OutputPort.cpp @@ -46,15 +46,24 @@ OutputPort::OutputPort(BufferFactory& bufs, if (type == PortType::CONTROL) _broadcast = true; + + setup_buffers(bufs, poly); +} + + +void +OutputPort::get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) +{ + for (uint32_t v = 0; v < poly; ++v) + buffers->at(v) = bufs.get(_type, _buffer_size); } void OutputPort::pre_process(Context& context) { - connect_buffers(); for (uint32_t v = 0; v < _poly; ++v) - buffer(v)->prepare_write(context); + _buffers->at(v)->prepare_write(context); } @@ -62,7 +71,7 @@ void OutputPort::post_process(Context& context) { for (uint32_t v = 0; v < _poly; ++v) - buffer(v)->prepare_read(context); + _buffers->at(v)->prepare_read(context); if (_broadcast) broadcast_value(context, false); diff --git a/src/engine/OutputPort.hpp b/src/engine/OutputPort.hpp index 8fdd4b2e..b143ae32 100644 --- a/src/engine/OutputPort.hpp +++ b/src/engine/OutputPort.hpp @@ -46,7 +46,9 @@ public: uint32_t poly, Shared::PortType type, const Raul::Atom& value, - size_t buffer_size); + size_t buffer_size=0); + + void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly); void pre_process(Context& context); void post_process(Context& context); diff --git a/src/engine/PatchImpl.cpp b/src/engine/PatchImpl.cpp index 46d04e8b..165f708f 100644 --- a/src/engine/PatchImpl.cpp +++ b/src/engine/PatchImpl.cpp @@ -27,6 +27,7 @@ #include "DuplexPort.hpp" #include "Engine.hpp" #include "ProcessSlave.hpp" +#include "Driver.hpp" #include "ingen-config.h" using namespace std; @@ -37,9 +38,9 @@ namespace Ingen { using namespace Shared; -PatchImpl::PatchImpl(Engine& engine, const Raul::Symbol& symbol, uint32_t poly, PatchImpl* parent, SampleRate srate, size_t buffer_size, uint32_t internal_poly) +PatchImpl::PatchImpl(Engine& engine, const Raul::Symbol& symbol, uint32_t poly, PatchImpl* parent, SampleRate srate, uint32_t internal_poly) : NodeBase(new PatchPlugin("http://example.org/FIXME", "patch", "Ingen Patch"), - symbol, poly, parent, srate, buffer_size) + symbol, poly, parent, srate) , _engine(engine) , _internal_poly(internal_poly) , _compiled_patch(NULL) @@ -59,12 +60,12 @@ PatchImpl::~PatchImpl() void -PatchImpl::activate() +PatchImpl::activate(BufferFactory& bufs) { - NodeBase::activate(); + NodeBase::activate(bufs); for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) - (*i)->activate(); + (*i)->activate(bufs); assert(_activated); } @@ -95,7 +96,8 @@ PatchImpl::disable() _process = false; for (List<PortImpl*>::iterator i = _output_ports.begin(); i != _output_ports.end(); ++i) - (*i)->clear_buffers(); + if ((*i)->context() == Context::AUDIO) + (*i)->clear_buffers(); } @@ -104,7 +106,7 @@ PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly) { ThreadManager::assert_thread(THREAD_PRE_PROCESS); - /* TODO: ports? internal/external poly? */ + // TODO: Subpatch dynamic polyphony (i.e. changing port polyphony) for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->prepare_poly(bufs, poly); @@ -112,22 +114,32 @@ PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly) for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) ((ConnectionImpl*)i->get())->prepare_poly(bufs, poly); - /* FIXME: Deal with failure */ - return true; } bool -PatchImpl::apply_internal_poly(Raul::Maid& maid, uint32_t poly) +PatchImpl::apply_internal_poly(BufferFactory& bufs, Raul::Maid& maid, uint32_t poly) { ThreadManager::assert_thread(THREAD_PROCESS); - /* TODO: ports? internal/external poly? */ + // TODO: Subpatch dynamic polyphony (i.e. changing port polyphony) for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) (*i)->apply_poly(maid, poly); + for (Connections::iterator i = _connections.begin(); i != _connections.end(); ++i) + ((ConnectionImpl*)i->get())->apply_poly(maid, poly); + + for (List<NodeImpl*>::iterator i = _nodes.begin(); i != _nodes.end(); ++i) { + for (uint32_t j = 0; j < (*i)->num_ports(); ++j) { + PortImpl* const port = (*i)->port_impl(j); + if (port->is_input() && dynamic_cast<InputPort*>(port)->num_connections() == 1) + port->setup_buffers(bufs, port->poly()); + port->connect_buffers(); + } + } + _internal_poly = poly; return true; @@ -239,23 +251,18 @@ PatchImpl::process_parallel(ProcessContext& context) void PatchImpl::process_single(ProcessContext& context) { - CompiledPatch* const cp = _compiled_patch; - - for (size_t i=0; i < cp->size(); ++i) - (*cp)[i].node()->process(context); + for (size_t i = 0; i < _compiled_patch->size(); ++i) + (*_compiled_patch)[i].node()->process(context); } void -PatchImpl::set_buffer_size(BufferFactory& bufs, size_t size) +PatchImpl::set_buffer_size(Context& context, BufferFactory& bufs, PortType type, size_t size) { - NodeBase::set_buffer_size(bufs, size); - assert(_buffer_size == size); - - CompiledPatch* const cp = _compiled_patch; + NodeBase::set_buffer_size(context, bufs, type, size); - for (size_t i=0; i < cp->size(); ++i) - (*cp)[i].node()->set_buffer_size(bufs, size); + for (size_t i = 0; i < _compiled_patch->size(); ++i) + (*_compiled_patch)[i].node()->set_buffer_size(context, bufs, type, size); } @@ -347,7 +354,7 @@ PatchImpl::num_ports() const /** Create a port. Not realtime safe. */ PortImpl* -PatchImpl::create_port(BufferFactory& bufs, const string& name, PortType type, size_t buffer_size, bool is_output) +PatchImpl::create_port(BufferFactory& bufs, const string& name, PortType type, size_t buffer_size, bool is_output, bool polyphonic) { if (type == PortType::UNKNOWN) { error << "[PatchImpl::create_port] Unknown port type " << type.uri() << endl; @@ -356,7 +363,8 @@ PatchImpl::create_port(BufferFactory& bufs, const string& name, PortType type, s assert( !(type == PortType::UNKNOWN) ); - return new DuplexPort(bufs, this, name, num_ports(), _polyphony, type, Raul::Atom(), buffer_size, is_output); + return new DuplexPort(bufs, this, name, num_ports(), polyphonic, _polyphony, + type, Raul::Atom(), buffer_size, is_output); } diff --git a/src/engine/PatchImpl.hpp b/src/engine/PatchImpl.hpp index 54839e92..c051f76b 100644 --- a/src/engine/PatchImpl.hpp +++ b/src/engine/PatchImpl.hpp @@ -31,9 +31,10 @@ namespace Ingen { namespace Shared { class Connection; } +class CompiledPatch; class ConnectionImpl; +class Context; class Engine; -class CompiledPatch; class ProcessContext; @@ -53,17 +54,16 @@ public: uint32_t poly, PatchImpl* parent, SampleRate srate, - size_t buffer_size, uint32_t local_poly); virtual ~PatchImpl(); - void activate(); + void activate(BufferFactory& bufs); void deactivate(); void process(ProcessContext& context); - void set_buffer_size(BufferFactory& bufs, size_t size); + void set_buffer_size(Context& context, BufferFactory& bufs, Shared::PortType type, size_t size); /** Prepare for a new (internal) polyphony value. * @@ -79,7 +79,7 @@ public: * \param poly Must be < the most recent value passed to prepare_internal_poly. * \param maid Any objects no longer needed will be pushed to this */ - bool apply_internal_poly(Raul::Maid& maid, uint32_t poly); + bool apply_internal_poly(BufferFactory& bufs, Raul::Maid& maid, uint32_t poly); // Patch specific stuff not inherited from Node @@ -96,7 +96,7 @@ public: uint32_t num_ports() const; - PortImpl* create_port(BufferFactory& bufs, const std::string& name, Shared::PortType type, size_t buffer_size, bool is_output); + PortImpl* create_port(BufferFactory& bufs, const std::string& name, Shared::PortType type, size_t buffer_size, bool is_output, bool polyphonic); void add_input(Raul::List<PortImpl*>::Node* port) { _input_ports.push_back(port); } ///< Preprocesser thread void add_output(Raul::List<PortImpl*>::Node* port) { _output_ports.push_back(port); } ///< Preprocessor thread Raul::List<PortImpl*>::Node* remove_port(const std::string& name); @@ -121,7 +121,7 @@ public: void enable() { _process = true; } void disable(); - uint32_t internal_polyphony() const { return _internal_poly; } + uint32_t internal_poly() const { return _internal_poly; } private: inline void compile_recursive(NodeImpl* n, CompiledPatch* output) const; diff --git a/src/engine/PortImpl.cpp b/src/engine/PortImpl.cpp index c7371aec..150934a4 100644 --- a/src/engine/PortImpl.cpp +++ b/src/engine/PortImpl.cpp @@ -23,14 +23,14 @@ #include "events/SendPortValue.hpp" #include "events/SendPortActivity.hpp" #include "AudioBuffer.hpp" -#include "EventBuffer.hpp" -#include "Engine.hpp" #include "BufferFactory.hpp" +#include "Engine.hpp" +#include "EventBuffer.hpp" #include "LV2Object.hpp" #include "NodeImpl.hpp" #include "ObjectBuffer.hpp" #include "PortImpl.hpp" -#include "ProcessContext.hpp" +#include "ThreadManager.hpp" using namespace std; using namespace Raul; @@ -48,7 +48,7 @@ PortImpl::PortImpl(BufferFactory& bufs, PortType type, const Atom& value, size_t buffer_size) - : GraphObjectImpl(node, name, (type == PortType::AUDIO || type == PortType::CONTROL)) + : GraphObjectImpl(node, name) , _bufs(bufs) , _index(index) , _poly(poly) @@ -59,22 +59,14 @@ PortImpl::PortImpl(BufferFactory& bufs, , _set_by_user(false) , _last_broadcasted_value(value) , _context(Context::AUDIO) - , _buffers(new Array<BufferFactory::Ref>(poly)) + , _buffers(new Array<BufferFactory::Ref>(static_cast<size_t>(poly))) , _prepared_buffers(NULL) { assert(node != NULL); assert(_poly > 0); - _buffers->alloc(_poly); - for (uint32_t v = 0; v < _poly; ++v) - _buffers->at(v) = bufs.get(_type, _buffer_size); - - _prepared_buffers = _buffers; - - if (node->parent() == NULL) - _polyphonic = false; - else - _polyphonic = true; + if (_buffer_size == 0) + _buffer_size = bufs.default_buffer_size(type); const LV2URIMap& uris = Shared::LV2URIMap::instance(); add_property(uris.rdf_type, type.uri()); @@ -83,44 +75,50 @@ PortImpl::PortImpl(BufferFactory& bufs, if (type == PortType::EVENTS) _broadcast = true; // send activity blips - - assert(_buffers->size() > 0); } PortImpl::~PortImpl() { - for (uint32_t v = 0; v < _poly; ++v) - _buffers->at(v).reset(NULL); // really old boost is missing this - //_buffers->at(v).reset(); // old boost is missing this - delete _buffers; } -bool -PortImpl::set_polyphonic(Maid& maid, bool p) +Raul::Array<BufferFactory::Ref>* +PortImpl::set_buffers(Raul::Array<BufferFactory::Ref>* buffers) { - if (_type == PortType::CONTROL || _type == PortType::AUDIO) - return GraphObjectImpl::set_polyphonic(maid, p); - else - return (!p); + ThreadManager::assert_thread(THREAD_PROCESS); + + Raul::Array<BufferFactory::Ref>* ret = NULL; + if (buffers != _buffers) { + ret = _buffers; + _buffers = buffers; + } + + connect_buffers(); + + return ret; } bool PortImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) { - if (!_polyphonic || !_parent->polyphonic()) - return true; - - /* FIXME: poly never goes down, harsh on memory.. */ - if (poly > _poly) { - _prepared_buffers = new Array<BufferFactory::Ref>(poly, *_buffers); - for (uint32_t i = _poly; i < _prepared_buffers->size(); ++i) - _prepared_buffers->at(i) = bufs.get(_type, _buffer_size); + ThreadManager::assert_thread(THREAD_PRE_PROCESS); + if (_type != PortType::CONTROL && _type != PortType::AUDIO) + return false; + + if (_prepared_buffers && _prepared_buffers->size() < poly) { + delete _prepared_buffers; + _prepared_buffers = NULL; } + if (!_prepared_buffers) + _prepared_buffers = new Array<BufferFactory::Ref>(poly, *_buffers, NULL); + + get_buffers(bufs, _prepared_buffers, poly); + assert(prepared_poly() == poly); + return true; } @@ -128,27 +126,28 @@ PortImpl::prepare_poly(BufferFactory& bufs, uint32_t poly) bool PortImpl::apply_poly(Maid& maid, uint32_t poly) { - if (!_polyphonic || !_parent->polyphonic()) - return true; + ThreadManager::assert_thread(THREAD_PROCESS); + if (_type != PortType::CONTROL && _type != PortType::AUDIO) + return false; assert(poly <= _prepared_buffers->size()); // Apply a new set of buffers from a preceding call to prepare_poly - if (_prepared_buffers && _buffers != _prepared_buffers) { - maid.push(_buffers); - _buffers = _prepared_buffers; - } + maid.push(set_buffers(_prepared_buffers)); + assert(_buffers == _prepared_buffers); + _prepared_buffers = NULL; _poly = poly; assert(_buffers->size() >= poly); assert(this->poly() == poly); + assert(!_prepared_buffers); return true; } void -PortImpl::set_buffer_size(BufferFactory& bufs, size_t size) +PortImpl::set_buffer_size(Context& context, BufferFactory& bufs, size_t size) { _buffer_size = size; @@ -168,6 +167,14 @@ PortImpl::connect_buffers() void +PortImpl::recycle_buffers() +{ + for (uint32_t v = 0; v < _poly; ++v) + _buffers->at(v) = NULL; +} + + +void PortImpl::clear_buffers() { for (uint32_t v = 0; v < _poly; ++v) diff --git a/src/engine/PortImpl.hpp b/src/engine/PortImpl.hpp index ceb556c1..ee61b367 100644 --- a/src/engine/PortImpl.hpp +++ b/src/engine/PortImpl.hpp @@ -35,7 +35,6 @@ namespace Ingen { class NodeImpl; class Buffer; -class ProcessContext; class BufferFactory; @@ -55,7 +54,12 @@ public: /** A port's parent is always a node, so static cast should be safe */ NodeImpl* parent_node() const { return (NodeImpl*)_parent; } - bool set_polyphonic(Raul::Maid& maid, bool p); + /** Set the buffers array for this port. + * + * Audio thread. Returned value must be freed by caller. + * \a buffers must be poly() long + */ + Raul::Array<BufferFactory::Ref>* set_buffers(Raul::Array<BufferFactory::Ref>* buffers); /** Prepare for a new (external) polyphony value. * @@ -66,7 +70,6 @@ public: /** Apply a new polyphony value. * * Audio thread. - * * \a poly Must be < the most recent value passed to prepare_poly. */ virtual bool apply_poly(Raul::Maid& maid, uint32_t poly); @@ -75,7 +78,7 @@ public: void set_value(const Raul::Atom& v) { _value = v; } inline BufferFactory::Ref buffer(uint32_t voice) const { - return _buffers->at(voice); + return _buffers->at((_poly == 1) ? 0 : voice); } inline BufferFactory::Ref prepared_buffer(uint32_t voice) const { return _prepared_buffers->at(voice); @@ -83,24 +86,36 @@ public: /** Called once per process cycle */ virtual void pre_process(Context& context) = 0; - virtual void process(ProcessContext& context) {}; virtual void post_process(Context& context) = 0; /** Empty buffer contents completely (ie silence) */ virtual void clear_buffers(); + + virtual void get_buffers(BufferFactory& bufs, Raul::Array<BufferFactory::Ref>* buffers, uint32_t poly) = 0; + + void setup_buffers(BufferFactory& bufs, uint32_t poly) { + get_buffers(bufs, _buffers, poly); + } + virtual void connect_buffers(); + virtual void recycle_buffers(); virtual bool is_input() const = 0; virtual bool is_output() const = 0; - uint32_t index() const { return _index; } - uint32_t poly() const { return _poly; } - Shared::PortType type() const { return _type; } - size_t buffer_size() const { - return (_type == Shared::PortType::CONTROL) ? 1 : _buffer_size; + uint32_t index() const { return _index; } + Shared::PortType type() const { return _type; } + + size_t buffer_size() const { return _buffer_size; } + + uint32_t poly() const { + return _poly; + } + uint32_t prepared_poly() const { + return (_prepared_buffers) ? _prepared_buffers->size() : 1; } - void set_buffer_size(BufferFactory& factory, size_t size); + void set_buffer_size(Context& context, BufferFactory& bufs, size_t size); void broadcast(bool b) { _broadcast = b; } bool broadcast() { return _broadcast; } diff --git a/src/engine/QueuedEngineInterface.cpp b/src/engine/QueuedEngineInterface.cpp index 58637d7c..138970ee 100644 --- a/src/engine/QueuedEngineInterface.cpp +++ b/src/engine/QueuedEngineInterface.cpp @@ -47,7 +47,7 @@ QueuedEngineInterface::now() const // Exactly one cycle latency (some could run ASAP if we get lucky, but not always, and a slight // constant latency is far better than jittery lower (average) latency if (_engine.driver()) - return _engine.driver()->frame_time() + _engine.driver()->buffer_size(); + return _engine.driver()->frame_time() + _engine.driver()->block_length(); else return 0; } diff --git a/src/engine/events/Connect.cpp b/src/engine/events/Connect.cpp index 1654645c..cc870c04 100644 --- a/src/engine/events/Connect.cpp +++ b/src/engine/events/Connect.cpp @@ -22,12 +22,14 @@ #include "ClientBroadcaster.hpp" #include "Connect.hpp" #include "ConnectionImpl.hpp" +#include "DuplexPort.hpp" #include "Engine.hpp" -#include "InputPort.hpp" #include "EngineStore.hpp" +#include "InputPort.hpp" #include "OutputPort.hpp" #include "PatchImpl.hpp" #include "PortImpl.hpp" +#include "ProcessContext.hpp" #include "Request.hpp" #include "types.hpp" @@ -50,6 +52,7 @@ Connect::Connect(Engine& engine, SharedPtr<Request> request, SampleCount timesta , _compiled_patch(NULL) , _patch_listnode(NULL) , _port_listnode(NULL) + , _buffers(NULL) , _error(NO_ERROR) { } @@ -157,6 +160,18 @@ Connect::pre_process() } _patch->add_connection(_patch_listnode); + _dst_input_port->increment_num_connections(); + + switch (_dst_input_port->num_connections()) { + case 1: + _connection->allocate_buffer(*_engine.buffer_factory()); + break; + case 2: + _buffers = new Raul::Array<BufferFactory::Ref>(_dst_input_port->poly()); + _dst_input_port->get_buffers(*_engine.buffer_factory(), _buffers, _dst_input_port->poly()); + default: + break; + } if (_patch->enabled()) _compiled_patch = _patch->compile(); @@ -173,8 +188,12 @@ Connect::execute(ProcessContext& context) if (_error == NO_ERROR) { // This must be inserted here, since they're actually used by the audio thread _dst_input_port->add_connection(_port_listnode); - if (_patch->compiled_patch() != NULL) - _engine.maid()->push(_patch->compiled_patch()); + if (_buffers) + _engine.maid()->push(_dst_input_port->set_buffers(_buffers)); + else + _dst_input_port->setup_buffers(*_engine.buffer_factory(), _dst_input_port->poly()); + _dst_input_port->connect_buffers(); + _engine.maid()->push(_patch->compiled_patch()); _patch->compiled_patch(_compiled_patch); } } diff --git a/src/engine/events/Connect.hpp b/src/engine/events/Connect.hpp index 7f88d160..116ea892 100644 --- a/src/engine/events/Connect.hpp +++ b/src/engine/events/Connect.hpp @@ -34,7 +34,6 @@ namespace Ingen { class PatchImpl; class NodeImpl; class ConnectionImpl; -class MidiMessage; class PortImpl; class InputPort; class OutputPort; @@ -57,7 +56,6 @@ public: void post_process(); private: - enum ErrorType { NO_ERROR, PARENT_PATCH_DIFFERENT, @@ -83,6 +81,8 @@ private: PatchImpl::Connections::Node* _patch_listnode; InputPort::Connections::Node* _port_listnode; + Raul::Array<BufferFactory::Ref>* _buffers; + ErrorType _error; }; diff --git a/src/engine/events/CreateNode.cpp b/src/engine/events/CreateNode.cpp index 4f5b4877..37adda6b 100644 --- a/src/engine/events/CreateNode.cpp +++ b/src/engine/events/CreateNode.cpp @@ -19,6 +19,7 @@ #include "raul/Path.hpp" #include "raul/Path.hpp" #include "redlandmm/World.hpp" +#include "shared/LV2URIMap.hpp" #include "CreateNode.hpp" #include "Request.hpp" #include "PatchImpl.hpp" @@ -46,12 +47,11 @@ CreateNode::CreateNode( SampleCount timestamp, const Path& path, const URI& plugin_uri, - bool polyphonic, const Resource::Properties& properties) : QueuedEvent(engine, request, timestamp) , _path(path) , _plugin_uri(plugin_uri) - , _polyphonic(polyphonic) + , _polyphonic(false) , _patch(NULL) , _plugin(NULL) , _node(NULL) @@ -69,6 +69,12 @@ CreateNode::CreateNode( _plugin_label = uri.substr(colon + 1); uri = ""; } + + const LV2URIMap& uris = Shared::LV2URIMap::instance(); + const Resource::Properties::const_iterator p = properties.find(uris.ingen_polyphonic); + if (p != properties.end() && p->second.type() == Raul::Atom::BOOL + && p->second.get_bool()) + _polyphonic = true; } @@ -93,7 +99,7 @@ CreateNode::pre_process() if (_node != NULL) { _node->properties().insert(_properties.begin(), _properties.end()); - _node->activate(); + _node->activate(*_engine.buffer_factory()); // This can be done here because the audio thread doesn't touch the // node tree - just the process order array @@ -116,9 +122,8 @@ CreateNode::execute(ProcessContext& context) { QueuedEvent::execute(context); - if (_node != NULL) { - if (_patch->compiled_patch() != NULL) - _engine.maid()->push(_patch->compiled_patch()); + if (_node) { + _engine.maid()->push(_patch->compiled_patch()); _patch->compiled_patch(_compiled_patch); } } diff --git a/src/engine/events/CreateNode.hpp b/src/engine/events/CreateNode.hpp index 4bb7e0b5..4c1b1238 100644 --- a/src/engine/events/CreateNode.hpp +++ b/src/engine/events/CreateNode.hpp @@ -45,7 +45,6 @@ public: SampleCount timestamp, const Raul::Path& node_path, const Raul::URI& plugin_uri, - bool poly, const Shared::Resource::Properties& properties); void pre_process(); diff --git a/src/engine/events/CreatePatch.cpp b/src/engine/events/CreatePatch.cpp index c90e2c17..f832c9fe 100644 --- a/src/engine/events/CreatePatch.cpp +++ b/src/engine/events/CreatePatch.cpp @@ -81,13 +81,13 @@ CreatePatch::pre_process() } uint32_t poly = 1; - if (_parent != NULL && _poly > 1 && _poly == static_cast<int>(_parent->internal_polyphony())) + if (_parent != NULL && _poly > 1 && _poly == static_cast<int>(_parent->internal_poly())) poly = _poly; const LV2URIMap& uris = *_engine.world()->uris.get(); _patch = new PatchImpl(_engine, path.symbol(), poly, _parent, - _engine.driver()->sample_rate(), _engine.driver()->buffer_size(), _poly); + _engine.driver()->sample_rate(), _poly); _patch->meta().properties().insert(_properties.begin(), _properties.end()); _patch->meta().set_property(uris.rdf_type, uris.ingen_Patch); _patch->set_property(uris.rdf_type, uris.ingen_Node); @@ -99,7 +99,7 @@ CreatePatch::pre_process() _compiled_patch = _parent->compile(); } - _patch->activate(); + _patch->activate(*_engine.buffer_factory()); // Insert into EngineStore //_patch->add_to_store(_engine.engine_store()); @@ -114,16 +114,15 @@ CreatePatch::execute(ProcessContext& context) { QueuedEvent::execute(context); - if (_patch != NULL) { - if (_parent == NULL) { + if (_patch) { + if (!_parent) { assert(_path.is_root()); assert(_patch->parent_patch() == NULL); _engine.driver()->set_root_patch(_patch); } else { - assert(_parent != NULL); + assert(_parent); assert(!_path.is_root()); - if (_parent->compiled_patch() != NULL) - _engine.maid()->push(_parent->compiled_patch()); + _engine.maid()->push(_parent->compiled_patch()); _parent->compiled_patch(_compiled_patch); } } diff --git a/src/engine/events/CreatePort.cpp b/src/engine/events/CreatePort.cpp index d2953c86..33a7f810 100644 --- a/src/engine/events/CreatePort.cpp +++ b/src/engine/events/CreatePort.cpp @@ -90,7 +90,7 @@ CreatePort::pre_process() if (_patch != NULL) { assert(_patch->path() == _path.parent()); - size_t buffer_size = _engine.driver()->buffer_size(); + size_t buffer_size = _engine.buffer_factory()->default_buffer_size(_data_type); const uint32_t old_num_ports = (_patch->external_ports()) ? _patch->external_ports()->size() @@ -104,7 +104,11 @@ CreatePort::pre_process() return; } - _patch_port = _patch->create_port(*_engine.buffer_factory(), _path.symbol(), _data_type, buffer_size, _is_output); + Shared::Resource::Properties::const_iterator poly_i = _properties.find(uris.ingen_polyphonic); + bool polyphonic = (poly_i != _properties.end() && poly_i->second.type() == Atom::BOOL + && poly_i->second.get_bool()); + + _patch_port = _patch->create_port(*_engine.buffer_factory(), _path.symbol(), _data_type, buffer_size, _is_output, polyphonic); if (_patch->parent()) _patch_port->set_property(uris.rdf_instanceOf, _patch_port->meta_uri()); @@ -121,7 +125,7 @@ CreatePort::pre_process() _patch->add_input(new Raul::List<PortImpl*>::Node(_patch_port)); if (_patch->external_ports()) - _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, *_patch->external_ports()); + _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, *_patch->external_ports(), NULL); else _ports_array = new Raul::Array<PortImpl*>(old_num_ports + 1, NULL); diff --git a/src/engine/events/Delete.cpp b/src/engine/events/Delete.cpp index 27f1b995..31e249f5 100644 --- a/src/engine/events/Delete.cpp +++ b/src/engine/events/Delete.cpp @@ -132,16 +132,15 @@ Delete::execute(ProcessContext& context) { QueuedEvent::execute(context); + PatchImpl* parent_patch = NULL; + if (_patch_node_listnode) { assert(_node); if (_disconnect_event) _disconnect_event->execute(context); - if (_node->parent_patch()->compiled_patch()) - _engine.maid()->push(_node->parent_patch()->compiled_patch()); - - _node->parent_patch()->compiled_patch(_compiled_patch); + parent_patch = _node->parent_patch(); } else if (_patch_port_listnode) { assert(_port); @@ -149,14 +148,9 @@ Delete::execute(ProcessContext& context) if (_disconnect_event) _disconnect_event->execute(context); - if (_port->parent_patch()->compiled_patch()) - _engine.maid()->push(_port->parent_patch()->compiled_patch()); - - _port->parent_patch()->compiled_patch(_compiled_patch); - - if (_port->parent_patch()->external_ports()) - _engine.maid()->push(_port->parent_patch()->external_ports()); + parent_patch = _port->parent_patch(); + _engine.maid()->push(_port->parent_patch()->external_ports()); _port->parent_patch()->external_ports(_ports_array); if ( ! _port->parent_patch()->parent()) { @@ -164,6 +158,11 @@ Delete::execute(ProcessContext& context) } } + if (parent_patch) { + _engine.maid()->push(parent_patch->compiled_patch()); + parent_patch->compiled_patch(_compiled_patch); + } + _request->unblock(); } @@ -174,7 +173,8 @@ Delete::post_process() _removed_bindings.reset(); if (_path.is_root() || _path == "path:/control_in" || _path == "path:/control_out") { - _request->respond_error(_path.chop_scheme() + " can not be deleted"); + // XXX: Just ignore? + //_request->respond_error(_path.chop_scheme() + " can not be deleted"); } else if (!_node && !_port) { string msg = string("Could not find object ") + _path.chop_scheme() + " to delete"; _request->respond_error(msg); diff --git a/src/engine/events/Disconnect.cpp b/src/engine/events/Disconnect.cpp index d1cfefe6..7454959e 100644 --- a/src/engine/events/Disconnect.cpp +++ b/src/engine/events/Disconnect.cpp @@ -19,15 +19,18 @@ #include "raul/Maid.hpp" #include "raul/Path.hpp" #include "events/Disconnect.hpp" -#include "Request.hpp" -#include "Engine.hpp" +#include "AudioBuffer.hpp" +#include "ClientBroadcaster.hpp" #include "ConnectionImpl.hpp" +#include "DuplexPort.hpp" +#include "Engine.hpp" +#include "EngineStore.hpp" #include "InputPort.hpp" #include "OutputPort.hpp" #include "PatchImpl.hpp" -#include "ClientBroadcaster.hpp" #include "PortImpl.hpp" -#include "EngineStore.hpp" +#include "ProcessContext.hpp" +#include "Request.hpp" using namespace std; using namespace Raul; @@ -48,10 +51,13 @@ Disconnect::Disconnect( , _patch(NULL) , _src_port(NULL) , _dst_port(NULL) - , _lookup(true) , _patch_connection(NULL) , _compiled_patch(NULL) + , _buffers(NULL) , _error(NO_ERROR) + , _internal(false) + , _reconnect_dst_port(true) + , _clear_dst_port(false) { } @@ -61,30 +67,28 @@ Disconnect::Disconnect( SharedPtr<Request> request, SampleCount timestamp, PortImpl* const src_port, - PortImpl* const dst_port) + PortImpl* const dst_port, + bool reconnect_dst_port) : QueuedEvent(engine, request, timestamp) , _src_port_path(src_port->path()) , _dst_port_path(dst_port->path()) , _patch(src_port->parent_node()->parent_patch()) , _src_port(src_port) , _dst_port(dst_port) - , _lookup(false) , _compiled_patch(NULL) + , _buffers(NULL) , _error(NO_ERROR) + , _internal(true) + , _reconnect_dst_port(reconnect_dst_port) + , _clear_dst_port(false) { - // FIXME: These break for patch ports.. is that ok? - /*assert(src_port->is_output()); - assert(dst_port->is_input()); - assert(src_port->type() == dst_port->type()); - assert(src_port->parent_node()->parent_patch() - == dst_port->parent_node()->parent_patch()); */ } void Disconnect::pre_process() { - if (_lookup) { + if (!_internal) { if (_src_port_path.parent().parent() != _dst_port_path.parent().parent() && _src_port_path.parent() != _dst_port_path.parent().parent() && _src_port_path.parent().parent() != _dst_port_path.parent()) { @@ -156,8 +160,16 @@ Disconnect::pre_process() } _patch_connection = _patch->remove_connection(_src_port, _dst_port); + _dst_input_port->decrement_num_connections(); - if (_patch->enabled()) + if (_dst_input_port->num_connections() == 0) { + _buffers = new Raul::Array<BufferFactory::Ref>(_dst_input_port->poly()); + _dst_input_port->get_buffers(*_engine.buffer_factory(), _buffers, _dst_input_port->poly()); + _clear_dst_port = true; + } + + + if (!_internal && _patch->enabled()) _compiled_patch = _patch->compile(); QueuedEvent::pre_process(); @@ -171,30 +183,41 @@ Disconnect::execute(ProcessContext& context) if (_error == NO_ERROR) { InputPort::Connections::Node* const port_connection - = _dst_input_port->remove_connection(_src_output_port); + = _dst_input_port->remove_connection(context, _src_output_port); + port_connection->elem()->recycle_buffer(); + if (_reconnect_dst_port) { + if (_buffers) + _engine.maid()->push(_dst_input_port->set_buffers(_buffers)); + else + _dst_input_port->setup_buffers(*_engine.buffer_factory(), _dst_input_port->poly()); + _dst_input_port->connect_buffers(); + if (_clear_dst_port) { + for (uint32_t v = 0; v < _dst_input_port->poly(); ++v) { + if (_dst_input_port->type() == PortType::CONTROL) { + PtrCast<AudioBuffer>(_dst_input_port->buffer(v))->set_value( + _dst_input_port->value().get_float(), + context.start(), context.start()); + } else { + _dst_input_port->buffer(v)->clear(); + } + } + } + } else { + _dst_input_port->recycle_buffers(); + } if (port_connection != NULL) { assert(_patch_connection); - - if (port_connection->elem() != _patch_connection->elem()) { - error << "Corrupt connections:" << endl - << "\t" << port_connection->elem() << ": " - << port_connection->elem()->src_port_path() - << " -> " << port_connection->elem()->dst_port_path() << endl - << "!=" << endl - << "\t" << _patch_connection->elem() << ": " - << _patch_connection->elem()->src_port_path() - << " -> " << _patch_connection->elem()->dst_port_path() << endl; - } assert(port_connection->elem() == _patch_connection->elem()); // Destroy list node, which will drop reference to connection itself _engine.maid()->push(port_connection); _engine.maid()->push(_patch_connection); - if (_patch->compiled_patch() != NULL) + if (!_internal) { _engine.maid()->push(_patch->compiled_patch()); - _patch->compiled_patch(_compiled_patch); + _patch->compiled_patch(_compiled_patch); + } } else { _error = CONNECTION_NOT_FOUND; } diff --git a/src/engine/events/Disconnect.hpp b/src/engine/events/Disconnect.hpp index 0bba8c7b..92f1bbc8 100644 --- a/src/engine/events/Disconnect.hpp +++ b/src/engine/events/Disconnect.hpp @@ -22,6 +22,7 @@ #include "QueuedEvent.hpp" #include "types.hpp" #include "PatchImpl.hpp" +#include "BufferFactory.hpp" namespace Raul { template <typename T> class ListNode; @@ -30,13 +31,10 @@ namespace Raul { namespace Ingen { -class NodeImpl; -class ConnectionImpl; -class MidiMessage; -class PortImpl; +class CompiledPatch; class InputPort; class OutputPort; -class CompiledPatch; +class PortImpl; namespace Events { @@ -60,7 +58,8 @@ public: SharedPtr<Request> request, SampleCount timestamp, PortImpl* const src_port, - PortImpl* const dst_port); + PortImpl* const dst_port, + bool reconnect_dst_port); void pre_process(); void execute(ProcessContext& context); @@ -87,12 +86,15 @@ private: OutputPort* _src_output_port; InputPort* _dst_input_port; - bool _lookup; - PatchImpl::Connections::Node* _patch_connection; CompiledPatch* _compiled_patch; ///< New process order for Patch + Raul::Array<BufferFactory::Ref>* _buffers; + ErrorType _error; + bool _internal; + bool _reconnect_dst_port; + bool _clear_dst_port; }; diff --git a/src/engine/events/DisconnectAll.cpp b/src/engine/events/DisconnectAll.cpp index af577199..56bef36a 100644 --- a/src/engine/events/DisconnectAll.cpp +++ b/src/engine/events/DisconnectAll.cpp @@ -48,8 +48,9 @@ DisconnectAll::DisconnectAll(Engine& engine, SharedPtr<Request> request, SampleC , _parent(NULL) , _node(NULL) , _port(NULL) - , _lookup(true) + , _compiled_patch(NULL) , _error(NO_ERROR) + , _deleting(false) { } @@ -63,8 +64,9 @@ DisconnectAll::DisconnectAll(Engine& engine, PatchImpl* parent, GraphObjectImpl* , _parent(parent) , _node(dynamic_cast<NodeImpl*>(object)) , _port(dynamic_cast<PortImpl*>(object)) - , _lookup(false) + , _compiled_patch(NULL) , _error(NO_ERROR) + , _deleting(true) { } @@ -79,7 +81,7 @@ DisconnectAll::~DisconnectAll() void DisconnectAll::pre_process() { - if (_lookup) { + if (!_deleting) { _parent = _engine.engine_store()->find_patch(_parent_path); if (_parent == NULL) { @@ -113,10 +115,11 @@ DisconnectAll::pre_process() for (PatchImpl::Connections::const_iterator i = _parent->connections().begin(); i != _parent->connections().end(); ++i) { ConnectionImpl* c = (ConnectionImpl*)i->get(); + const bool reconnect_input = !_deleting || (c->dst_port()->parent_node() != _node); if ((c->src_port()->parent_node() == _node || c->dst_port()->parent_node() == _node) && !c->pending_disconnection()) { Disconnect* ev = new Disconnect(_engine, - SharedPtr<Request>(), _time, c->src_port(), c->dst_port()); + SharedPtr<Request>(), _time, c->src_port(), c->dst_port(), reconnect_input); ev->pre_process(); _disconnect_events.push_back(new Raul::List<Disconnect*>::Node(ev)); c->pending_disconnection(true); @@ -126,9 +129,10 @@ DisconnectAll::pre_process() for (PatchImpl::Connections::const_iterator i = _parent->connections().begin(); i != _parent->connections().end(); ++i) { ConnectionImpl* c = (ConnectionImpl*)i->get(); + const bool reconnect_input = !_deleting || (c->dst_port()->parent_node() != _node); if ((c->src_port() == _port || c->dst_port() == _port) && !c->pending_disconnection()) { Disconnect* ev = new Disconnect(_engine, - SharedPtr<Request>(), _time, c->src_port(), c->dst_port()); + SharedPtr<Request>(), _time, c->src_port(), c->dst_port(), reconnect_input); ev->pre_process(); _disconnect_events.push_back(new Raul::List<Disconnect*>::Node(ev)); c->pending_disconnection(true); @@ -136,6 +140,9 @@ DisconnectAll::pre_process() } } + if (!_deleting && _parent->enabled()) + _compiled_patch = _parent->compile(); + QueuedEvent::pre_process(); } @@ -146,9 +153,13 @@ DisconnectAll::execute(ProcessContext& context) QueuedEvent::execute(context); if (_error == NO_ERROR) { - for (Raul::List<Disconnect*>::iterator i = _disconnect_events.begin(); i != _disconnect_events.end(); ++i) + for (Raul::List<Disconnect*>::iterator i = _disconnect_events.begin(); + i != _disconnect_events.end(); ++i) (*i)->execute(context); } + + _engine.maid()->push(_parent->compiled_patch()); + _parent->compiled_patch(_compiled_patch); } diff --git a/src/engine/events/DisconnectAll.hpp b/src/engine/events/DisconnectAll.hpp index 300f3213..47f5576a 100644 --- a/src/engine/events/DisconnectAll.hpp +++ b/src/engine/events/DisconnectAll.hpp @@ -24,12 +24,10 @@ namespace Ingen { -class PatchImpl; +class CompiledPatch; class NodeImpl; -class Connection; +class PatchImpl; class PortImpl; -class InputPort; -class OutputPort; namespace Events { @@ -76,10 +74,10 @@ private: PortImpl* _port; Raul::List<Disconnect*> _disconnect_events; - bool _lookup; - bool _disconnect_parent; + CompiledPatch* _compiled_patch; ///< New process order for Patch ErrorType _error; + bool _deleting; }; diff --git a/src/engine/events/SetMetadata.cpp b/src/engine/events/SetMetadata.cpp index cc3eb61f..70463aa6 100644 --- a/src/engine/events/SetMetadata.cpp +++ b/src/engine/events/SetMetadata.cpp @@ -18,6 +18,7 @@ #include <string> #include <boost/format.hpp> #include "raul/log.hpp" +#include "raul/Maid.hpp" #include "interface/PortType.hpp" #include "shared/LV2URIMap.hpp" #include "ClientBroadcaster.hpp" @@ -68,19 +69,19 @@ SetMetadata::SetMetadata( , _create(create) , _is_meta(meta) { -#if 0 - LOG(debug) << "Set " << subject << " {" << endl; + /* + LOG(info) << "Set " << subject << " {" << endl; typedef Resource::Properties::const_iterator iterator; for (iterator i = properties.begin(); i != properties.end(); ++i) - LOG(debug) << " " << i->first << " = " << i->second << " :: " << i->second.type() << endl; - LOG(debug) << "}" << endl; + LOG(info) << " " << i->first << " = " << i->second << " :: " << i->second.type() << endl; + LOG(info) << "}" << endl; - LOG(debug) << "Unset " << subject << " {" << endl; + LOG(info) << "Unset " << subject << " {" << endl; typedef Resource::Properties::const_iterator iterator; for (iterator i = remove.begin(); i != remove.end(); ++i) - LOG(debug) << " " << i->first << " = " << i->second << " :: " << i->second.type() << endl; - LOG(debug) << "}" << endl; -#endif + LOG(info) << " " << i->first << " = " << i->second << " :: " << i->second.type() << endl; + LOG(info) << "}" << endl; + */ } @@ -131,7 +132,7 @@ SetMetadata::pre_process() } else if (is_node) { const iterator p = _properties.find(uris.rdf_instanceOf); _create_event = new CreateNode(_engine, sub_request, _time, - path, p->second.get_uri(), true, _properties); + path, p->second.get_uri(), _properties); } else if (is_port) { _blocking = bool(_request); _create_event = new CreatePort(_engine, sub_request, _time, @@ -159,6 +160,18 @@ SetMetadata::pre_process() obj->properties().erase(p->first); #endif + for (Properties::const_iterator p = _remove.begin(); p != _remove.end(); ++p) { + const Raul::URI& key = p->first; + const Raul::Atom& value = p->second; + if (key == uris.ingen_controlBinding && value == uris.wildcard) { + PortImpl* port = dynamic_cast<PortImpl*>(_object); + if (port) + _old_bindings = _engine.control_bindings()->remove(port); + } + _object->remove_property(key, value); + } + + for (Properties::iterator p = _properties.begin(); p != _properties.end(); ++p) { const Raul::URI& key = p->first; const Raul::Atom& value = p->second; @@ -176,17 +189,11 @@ SetMetadata::pre_process() _error = BAD_VALUE_TYPE; } } else if (key == uris.ingen_value) { - PortImpl* port = dynamic_cast<PortImpl*>(_object); - if (port) { - SetPortValue* ev = new SetPortValue(_engine, _request, _time, port, value); - ev->pre_process(); - _set_events.push_back(ev); - } else { - _error = BAD_OBJECT_TYPE; - } + SetPortValue* ev = new SetPortValue(_engine, _request, _time, port, value); + ev->pre_process(); + _set_events.push_back(ev); } else if (key == uris.ingen_controlBinding) { - PortImpl* port = dynamic_cast<PortImpl*>(_object); - if (port && port->type() == Shared::PortType::CONTROL) { + if (port->type() == Shared::PortType::CONTROL) { if (value == uris.wildcard) { _engine.control_bindings()->learn(port); } else if (value.type() == Atom::DICT) { @@ -202,17 +209,12 @@ SetMetadata::pre_process() if (key == uris.ingen_enabled) { if (value.type() == Atom::BOOL) { op = ENABLE; - if (value.get_bool() && !_patch->compiled_patch()) + // FIXME: defer this until all other metadata has been processed + if (value.get_bool() && !_patch->enabled()) _compiled_patch = _patch->compile(); } else { _error = BAD_VALUE_TYPE; } - } else if (key == uris.ingen_polyphonic) { - if (value.type() == Atom::BOOL) { - op = POLYPHONIC; - } else { - _error = BAD_VALUE_TYPE; - } } else if (key == uris.ingen_polyphony) { if (value.type() == Atom::INT) { op = POLYPHONY; @@ -222,6 +224,27 @@ SetMetadata::pre_process() _error = BAD_VALUE_TYPE; } } + } else if (key == uris.ingen_polyphonic) { + PatchImpl* parent = dynamic_cast<PatchImpl*>(obj->parent()); + if (parent) { + if (value.type() == Atom::BOOL) { + op = POLYPHONIC; + _blocking = true; + obj->set_property(key, value.get_bool()); + NodeBase* node = dynamic_cast<NodeBase*>(obj); + if (node) + node->set_polyphonic(value.get_bool()); + if (value.get_bool()) { + obj->prepare_poly(*_engine.buffer_factory(), parent->internal_poly()); + } else { + obj->prepare_poly(*_engine.buffer_factory(), 1); + } + } else { + _error = BAD_VALUE_TYPE; + } + } else { + _error = BAD_OBJECT_TYPE; + } } } @@ -233,17 +256,6 @@ SetMetadata::pre_process() _types.push_back(op); } - for (Properties::iterator p = _remove.begin(); p != _remove.end(); ++p) { - const Raul::URI& key = p->first; - const Raul::Atom& value = p->second; - if (key == uris.ingen_controlBinding && value == uris.wildcard) { - PortImpl* port = dynamic_cast<PortImpl*>(_object); - if (port) - _old_bindings = _engine.control_bindings()->remove(port); - } - _object->remove_property(key, value); - } - QueuedEvent::pre_process(); } @@ -281,21 +293,30 @@ SetMetadata::execute(ProcessContext& context) break; case ENABLE: if (value.get_bool()) { - if (!_patch->compiled_patch()) + if (_compiled_patch) { + _engine.maid()->push(_patch->compiled_patch()); _patch->compiled_patch(_compiled_patch); + } _patch->enable(); } else { _patch->disable(); } break; case POLYPHONIC: - if (object) - if (!object->set_polyphonic(*_engine.maid(), value.get_bool())) - _error = INTERNAL; + { + PatchImpl* parent = reinterpret_cast<PatchImpl*>(object->parent()); + if (value.get_bool()) + object->apply_poly(*_engine.maid(), parent->internal_poly()); + else + object->apply_poly(*_engine.maid(), 1); + } break; case POLYPHONY: - if (!_patch->apply_internal_poly(*_engine.maid(), value.get_int32())) + if (_patch->internal_poly() != static_cast<uint32_t>(value.get_int32()) && + !_patch->apply_internal_poly(*_engine.buffer_factory(), + *_engine.maid(), value.get_int32())) { _error = INTERNAL; + } break; case CONTROL_BINDING: if (port) { @@ -311,9 +332,6 @@ SetMetadata::execute(ProcessContext& context) } } - for (Properties::const_iterator p = _remove.begin(); p != _remove.end(); ++p, ++t) - _object->remove_property(p->first, p->second); - QueuedEvent::execute(context); if (_blocking) diff --git a/src/engine/events/SetPortValue.cpp b/src/engine/events/SetPortValue.cpp index a43a37aa..d919814e 100644 --- a/src/engine/events/SetPortValue.cpp +++ b/src/engine/events/SetPortValue.cpp @@ -99,7 +99,7 @@ SetPortValue::pre_process() apply(*_engine.message_context()); _port->parent_node()->set_port_valid(_port->index()); _engine.message_context()->run(_port, - _engine.driver()->frame_time() + _engine.driver()->buffer_size()); + _engine.driver()->frame_time() + _engine.driver()->block_length()); } if (_port) { diff --git a/src/engine/internals/Controller.cpp b/src/engine/internals/Controller.cpp index 3d856fe0..870dfc8e 100644 --- a/src/engine/internals/Controller.cpp +++ b/src/engine/internals/Controller.cpp @@ -44,39 +44,38 @@ ControllerNode::ControllerNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, - SampleRate srate, - size_t buffer_size) - : NodeBase(&controller_plugin, path, false, parent, srate, buffer_size) + SampleRate srate) + : NodeBase(&controller_plugin, path, false, parent, srate) , _learning(false) { const LV2URIMap& uris = Shared::LV2URIMap::instance(); _ports = new Raul::Array<PortImpl*>(6); - _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom(), _buffer_size); + _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom()); _midi_in_port->set_property(uris.lv2_name, "Input"); _ports->at(0) = _midi_in_port; - _param_port = new InputPort(bufs, this, "controller", 1, 1, PortType::CONTROL, 0.0f, sizeof(Sample)); + _param_port = new InputPort(bufs, this, "controller", 1, 1, PortType::CONTROL, 0.0f); _param_port->set_property(uris.lv2_minimum, 0.0f); _param_port->set_property(uris.lv2_maximum, 127.0f); _param_port->set_property(uris.lv2_integer, true); _param_port->set_property(uris.lv2_name, "Controller"); _ports->at(1) = _param_port; - _log_port = new InputPort(bufs, this, "logarithmic", 2, 1, PortType::CONTROL, 0.0f, sizeof(Sample)); + _log_port = new InputPort(bufs, this, "logarithmic", 2, 1, PortType::CONTROL, 0.0f); _log_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _log_port->set_property(uris.lv2_name, "Logarithmic"); _ports->at(2) = _log_port; - _min_port = new InputPort(bufs, this, "minimum", 3, 1, PortType::CONTROL, 0.0f, sizeof(Sample)); + _min_port = new InputPort(bufs, this, "minimum", 3, 1, PortType::CONTROL, 0.0f); _min_port->set_property(uris.lv2_name, "Minimum"); _ports->at(3) = _min_port; - _max_port = new InputPort(bufs, this, "maximum", 4, 1, PortType::CONTROL, 1.0f, sizeof(Sample)); + _max_port = new InputPort(bufs, this, "maximum", 4, 1, PortType::CONTROL, 1.0f); _max_port->set_property(uris.lv2_name, "Maximum"); _ports->at(4) = _max_port; - _audio_port = new OutputPort(bufs, this, "ar_output", 5, 1, PortType::AUDIO, 0.0f, _buffer_size); + _audio_port = new OutputPort(bufs, this, "ar_output", 5, 1, PortType::AUDIO, 0.0f); _audio_port->set_property(uris.lv2_name, "Output"); _ports->at(5) = _audio_port; } @@ -112,8 +111,6 @@ ControllerNode::process(ProcessContext& context) void ControllerNode::control(ProcessContext& context, uint8_t control_num, uint8_t val, FrameTime time) { - assert(time - context.start() < _buffer_size); - Sample scaled_value; const Sample nval = (val / 127.0f); // normalized [0, 1] diff --git a/src/engine/internals/Controller.hpp b/src/engine/internals/Controller.hpp index 9482916e..b6d7302f 100644 --- a/src/engine/internals/Controller.hpp +++ b/src/engine/internals/Controller.hpp @@ -40,7 +40,7 @@ namespace Internals { class ControllerNode : public NodeBase { public: - ControllerNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size); + ControllerNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate); void process(ProcessContext& context); diff --git a/src/engine/internals/Note.cpp b/src/engine/internals/Note.cpp index a400e3c4..2798a948 100644 --- a/src/engine/internals/Note.cpp +++ b/src/engine/internals/Note.cpp @@ -47,8 +47,8 @@ static InternalPlugin note_plugin(NS_INTERNALS "Note", "note"); InternalPlugin& NoteNode::internal_plugin() { return note_plugin; } -NoteNode::NoteNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) - : NodeBase(¬e_plugin, path, polyphonic, parent, srate, buffer_size) +NoteNode::NoteNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate) + : NodeBase(¬e_plugin, path, polyphonic, parent, srate) , _voices(new Raul::Array<Voice>(_polyphony)) , _prepared_voices(NULL) , _sustain(false) @@ -56,26 +56,26 @@ NoteNode::NoteNode(BufferFactory& bufs, const string& path, bool polyphonic, Pat const LV2URIMap& uris = Shared::LV2URIMap::instance(); _ports = new Raul::Array<PortImpl*>(5); - _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom(), _buffer_size); + _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom()); _midi_in_port->set_property(uris.lv2_name, "Input"); _ports->at(0) = _midi_in_port; - _freq_port = new OutputPort(bufs, this, "frequency", 1, _polyphony, PortType::AUDIO, 440.0f, _buffer_size); + _freq_port = new OutputPort(bufs, this, "frequency", 1, _polyphony, PortType::AUDIO, 440.0f); _freq_port->set_property(uris.lv2_name, "Frequency"); _ports->at(1) = _freq_port; - _vel_port = new OutputPort(bufs, this, "velocity", 2, _polyphony, PortType::AUDIO, 0.0f, _buffer_size); + _vel_port = new OutputPort(bufs, this, "velocity", 2, _polyphony, PortType::AUDIO, 0.0f); _vel_port->set_property(uris.lv2_minimum, 0.0f); _vel_port->set_property(uris.lv2_maximum, 1.0f); _vel_port->set_property(uris.lv2_name, "Velocity"); _ports->at(2) = _vel_port; - _gate_port = new OutputPort(bufs, this, "gate", 3, _polyphony, PortType::AUDIO, 0.0f, _buffer_size); + _gate_port = new OutputPort(bufs, this, "gate", 3, _polyphony, PortType::AUDIO, 0.0f); _gate_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _gate_port->set_property(uris.lv2_name, "Gate"); _ports->at(3) = _gate_port; - _trig_port = new OutputPort(bufs, this, "trigger", 4, _polyphony, PortType::AUDIO, 0.0f, _buffer_size); + _trig_port = new OutputPort(bufs, this, "trigger", 4, _polyphony, PortType::AUDIO, 0.0f); _trig_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _trig_port->set_property(uris.lv2_name, "Trigger"); _ports->at(4) = _trig_port; @@ -99,7 +99,7 @@ NoteNode::prepare_poly(BufferFactory& bufs, uint32_t poly) if (_prepared_voices && poly <= _prepared_voices->size()) return true; - _prepared_voices = new Raul::Array<Voice>(poly, *_voices); + _prepared_voices = new Raul::Array<Voice>(poly, *_voices, Voice()); return true; } @@ -108,20 +108,16 @@ NoteNode::prepare_poly(BufferFactory& bufs, uint32_t poly) bool NoteNode::apply_poly(Raul::Maid& maid, uint32_t poly) { - if (!_polyphonic) - return true; - - NodeBase::apply_poly(maid, poly); + if (!NodeBase::apply_poly(maid, poly)) + return false; if (_prepared_voices) { - assert(poly <= _prepared_voices->size()); + assert(_polyphony <= _prepared_voices->size()); maid.push(_voices); _voices = _prepared_voices; _prepared_voices = NULL; } - - _polyphony = poly; - assert(_voices->size() >= _polyphony); + assert(_polyphony <= _voices->size()); return true; } @@ -202,7 +198,6 @@ void NoteNode::note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); assert(note_num <= 127); Key* key = &_keys[note_num]; @@ -293,7 +288,6 @@ void NoteNode::note_off(ProcessContext& context, uint8_t note_num, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); Key* key = &_keys[note_num]; @@ -333,7 +327,6 @@ void NoteNode::free_voice(ProcessContext& context, uint32_t voice, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); // Find a key to reassign to the freed voice (the newest, if there is one) Key* replace_key = NULL; @@ -375,7 +368,6 @@ void NoteNode::all_notes_off(ProcessContext& context, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); #ifdef LOG_DEBUG LOG(debug) << "All notes off @ " << time << endl; @@ -411,7 +403,6 @@ void NoteNode::sustain_off(ProcessContext& context, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); _sustain = false; diff --git a/src/engine/internals/Note.hpp b/src/engine/internals/Note.hpp index 11fc1344..8ad7f452 100644 --- a/src/engine/internals/Note.hpp +++ b/src/engine/internals/Note.hpp @@ -40,7 +40,7 @@ namespace Internals { class NoteNode : public NodeBase { public: - NoteNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size); + NoteNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate); ~NoteNode(); bool prepare_poly(BufferFactory& bufs, uint32_t poly); @@ -68,7 +68,7 @@ private: /** Voice, one of these always exists for each voice */ struct Voice { enum State { FREE, ACTIVE, HOLDING }; - Voice() : state(FREE), note(0) {} + Voice() : state(FREE), note(0), time(0) {} State state; uint8_t note; SampleCount time; }; diff --git a/src/engine/internals/Trigger.cpp b/src/engine/internals/Trigger.cpp index eded1ac7..c8d6b77e 100644 --- a/src/engine/internals/Trigger.cpp +++ b/src/engine/internals/Trigger.cpp @@ -43,35 +43,35 @@ static InternalPlugin trigger_plugin(NS_INTERNALS "Trigger", "trigger"); InternalPlugin& TriggerNode::internal_plugin() { return trigger_plugin; } -TriggerNode::TriggerNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size) - : NodeBase(&trigger_plugin, path, false, parent, srate, buffer_size) +TriggerNode::TriggerNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate) + : NodeBase(&trigger_plugin, path, false, parent, srate) , _learning(false) { const LV2URIMap& uris = LV2URIMap::instance(); _ports = new Raul::Array<PortImpl*>(5); - _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom(), _buffer_size); + _midi_in_port = new InputPort(bufs, this, "input", 0, 1, PortType::EVENTS, Raul::Atom()); _midi_in_port->set_property(uris.lv2_name, "Input"); _ports->at(0) = _midi_in_port; - _note_port = new InputPort(bufs, this, "note", 1, 1, PortType::CONTROL, 60.0f, sizeof(Sample)); + _note_port = new InputPort(bufs, this, "note", 1, 1, PortType::CONTROL, 60.0f); _note_port->set_property(uris.lv2_minimum, 0.0f); _note_port->set_property(uris.lv2_maximum, 127.0f); _note_port->set_property(uris.lv2_integer, true); _note_port->set_property(uris.lv2_name, "Note"); _ports->at(1) = _note_port; - _gate_port = new OutputPort(bufs, this, "gate", 2, 1, PortType::AUDIO, 0.0f, _buffer_size); + _gate_port = new OutputPort(bufs, this, "gate", 2, 1, PortType::AUDIO, 0.0f); _gate_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _gate_port->set_property(uris.lv2_name, "Gate"); _ports->at(2) = _gate_port; - _trig_port = new OutputPort(bufs, this, "trigger", 3, 1, PortType::AUDIO, 0.0f, _buffer_size); + _trig_port = new OutputPort(bufs, this, "trigger", 3, 1, PortType::AUDIO, 0.0f); _trig_port->set_property(uris.lv2_portProperty, uris.lv2_toggled); _trig_port->set_property(uris.lv2_name, "Trigger"); _ports->at(3) = _trig_port; - _vel_port = new OutputPort(bufs, this, "velocity", 4, 1, PortType::AUDIO, 0.0f, _buffer_size); + _vel_port = new OutputPort(bufs, this, "velocity", 4, 1, PortType::AUDIO, 0.0f); _vel_port->set_property(uris.lv2_minimum, 0.0f); _vel_port->set_property(uris.lv2_maximum, 1.0f); _vel_port->set_property(uris.lv2_name, "Velocity"); @@ -128,7 +128,6 @@ void TriggerNode::note_on(ProcessContext& context, uint8_t note_num, uint8_t velocity, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); if (_learning) { _note_port->set_value(note_num); @@ -157,7 +156,6 @@ void TriggerNode::note_off(ProcessContext& context, uint8_t note_num, FrameTime time) { assert(time >= context.start() && time <= context.end()); - assert(time - context.start() < _buffer_size); if (note_num == lrintf(((AudioBuffer*)_note_port->buffer(0).get())->value_at(0))) ((AudioBuffer*)_gate_port->buffer(0).get())->set_value(0.0f, context.start(), time); diff --git a/src/engine/internals/Trigger.hpp b/src/engine/internals/Trigger.hpp index 12e5c140..53aba06f 100644 --- a/src/engine/internals/Trigger.hpp +++ b/src/engine/internals/Trigger.hpp @@ -43,7 +43,7 @@ namespace Internals { class TriggerNode : public NodeBase { public: - TriggerNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate, size_t buffer_size); + TriggerNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate); void process(ProcessContext& context); diff --git a/src/engine/tuning.hpp b/src/engine/tuning.hpp index 70538c25..4bfb1c16 100644 --- a/src/engine/tuning.hpp +++ b/src/engine/tuning.hpp @@ -34,6 +34,8 @@ static const size_t message_context_queue_size = 1024; //static const timespec main_rate = { 0, 500000000 }; // 1/2 second static const timespec main_rate = { 0, 125000000 }; // 1/8 second +static const size_t event_bytes_per_frame = 4; + } // namespace Ingen diff --git a/src/gui/LoadPatchWindow.cpp b/src/gui/LoadPatchWindow.cpp index b504822f..c274a30d 100644 --- a/src/gui/LoadPatchWindow.cpp +++ b/src/gui/LoadPatchWindow.cpp @@ -120,7 +120,7 @@ LoadPatchWindow::set_patch(SharedPtr<PatchModel> patch) _patch = patch; _symbol_entry->set_text(""); _symbol_entry->set_sensitive(!_import); - _poly_spinbutton->set_value(patch->poly()); + _poly_spinbutton->set_value(patch->internal_poly()); } diff --git a/src/gui/NodeModule.cpp b/src/gui/NodeModule.cpp index 482cbe95..68f66c70 100644 --- a/src/gui/NodeModule.cpp +++ b/src/gui/NodeModule.cpp @@ -390,10 +390,13 @@ NodeModule::store_location() if (existing_x.type() != Atom::FLOAT || existing_y.type() != Atom::FLOAT || existing_x.get_float() != x || existing_y.get_float() != y) { - Shared::Resource::Properties props; - props.insert(make_pair(uris.ingenui_canvas_x, Atom(x))); - props.insert(make_pair(uris.ingenui_canvas_y, Atom(y))); - App::instance().engine()->put(_node->path(), props); + Shared::Resource::Properties remove; + remove.insert(make_pair(uris.ingenui_canvas_x, uris.wildcard)); + remove.insert(make_pair(uris.ingenui_canvas_y, uris.wildcard)); + Shared::Resource::Properties add; + add.insert(make_pair(uris.ingenui_canvas_x, Atom(x))); + add.insert(make_pair(uris.ingenui_canvas_y, Atom(y))); + App::instance().engine()->delta(_node->path(), remove, add); } } diff --git a/src/gui/PatchCanvas.cpp b/src/gui/PatchCanvas.cpp index 3c30910a..0762718b 100644 --- a/src/gui/PatchCanvas.cpp +++ b/src/gui/PatchCanvas.cpp @@ -658,7 +658,7 @@ PatchCanvas::paste() string created = "/"; Resource::Properties props; props.insert(make_pair(uris.rdf_type, uris.ingen_Patch)); - props.insert(make_pair(uris.ingen_polyphony, Raul::Atom(int32_t(_patch->poly())))); + props.insert(make_pair(uris.ingen_polyphony, Raul::Atom(int32_t(_patch->internal_poly())))); clipboard.put(Path(), props); size_t first_slash; while (to_create != "/" && !to_create.empty() diff --git a/src/gui/PatchView.cpp b/src/gui/PatchView.cpp index e420793a..9b9935c9 100644 --- a/src/gui/PatchView.cpp +++ b/src/gui/PatchView.cpp @@ -75,7 +75,7 @@ PatchView::set_patch(SharedPtr<PatchModel> patch) _canvas_scrolledwindow->add(*_canvas); - _poly_spin->set_value(patch->poly()); + _poly_spin->set_value(patch->internal_poly()); for (GraphObject::Properties::const_iterator i = patch->meta().properties().begin(); i != patch->meta().properties().end(); ++i) diff --git a/src/gui/WindowFactory.cpp b/src/gui/WindowFactory.cpp index 7b5b6000..fdc2f029 100644 --- a/src/gui/WindowFactory.cpp +++ b/src/gui/WindowFactory.cpp @@ -213,7 +213,7 @@ WindowFactory::new_control_window(SharedPtr<NodeModel> node) { uint32_t poly = 1; if (node->polyphonic() && node->parent()) - poly = ((PatchModel*)node->parent().get())->internal_polyphony(); + poly = ((PatchModel*)node->parent().get())->internal_poly(); NodeControlWindow* win = new NodeControlWindow(node, poly); diff --git a/src/serialisation/Serialiser.cpp b/src/serialisation/Serialiser.cpp index 35d304f8..d1f19e9c 100644 --- a/src/serialisation/Serialiser.cpp +++ b/src/serialisation/Serialiser.cpp @@ -48,6 +48,9 @@ #include "shared/LV2URIMap.hpp" #include "Serialiser.hpp" + +#include "/home/dave/code/lad/trunk/ingen/src/client/NodeModel.hpp" + #define LOG(s) s << "[Serialiser] " using namespace std; diff --git a/src/shared/Builder.cpp b/src/shared/Builder.cpp index 542176d0..c8d48479 100644 --- a/src/shared/Builder.cpp +++ b/src/shared/Builder.cpp @@ -47,7 +47,7 @@ Builder::build(SharedPtr<const GraphObject> object) if (!object->path().is_root()) { Resource::Properties props; props.insert(make_pair(uris.rdf_type, uris.ingen_Patch)); - props.insert(make_pair(uris.ingen_polyphony, Atom(int32_t(patch->internal_polyphony())))); + props.insert(make_pair(uris.ingen_polyphony, Atom(int32_t(patch->internal_poly())))); _interface.put(object->path(), props); } diff --git a/src/shared/ResourceImpl.cpp b/src/shared/ResourceImpl.cpp index 230d53b8..b542ff2d 100644 --- a/src/shared/ResourceImpl.cpp +++ b/src/shared/ResourceImpl.cpp @@ -217,7 +217,6 @@ ResourceImpl::remove_properties(const Properties& p) void - ResourceImpl::dump(std::ostream& os) const { typedef Resource::Properties::const_iterator iterator; |