summaryrefslogtreecommitdiffstats
path: root/src/engine
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2010-02-20 21:52:36 +0000
committerDavid Robillard <d@drobilla.net>2010-02-20 21:52:36 +0000
commit46e5de590817756b21a7a5d99bd4963df343f455 (patch)
tree7d7b3b63297b24d84e5b42cc8aeb22d4212738b5 /src/engine
parentb96a4015ae39b5bdd9afbd82898c0168a0a8e613 (diff)
downloadingen-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
Diffstat (limited to 'src/engine')
-rw-r--r--src/engine/AudioBuffer.cpp15
-rw-r--r--src/engine/AudioBuffer.hpp2
-rw-r--r--src/engine/Buffer.hpp4
-rw-r--r--src/engine/BufferFactory.cpp50
-rw-r--r--src/engine/BufferFactory.hpp11
-rw-r--r--src/engine/ConnectionImpl.cpp43
-rw-r--r--src/engine/ConnectionImpl.hpp7
-rw-r--r--src/engine/Driver.hpp4
-rw-r--r--src/engine/DuplexPort.cpp13
-rw-r--r--src/engine/DuplexPort.hpp3
-rw-r--r--src/engine/Engine.cpp7
-rw-r--r--src/engine/EventBuffer.cpp4
-rw-r--r--src/engine/EventBuffer.hpp2
-rw-r--r--src/engine/GraphObjectImpl.cpp3
-rw-r--r--src/engine/GraphObjectImpl.hpp25
-rw-r--r--src/engine/InputPort.cpp126
-rw-r--r--src/engine/InputPort.hpp22
-rw-r--r--src/engine/InternalPlugin.cpp9
-rw-r--r--src/engine/JackDriver.cpp22
-rw-r--r--src/engine/JackDriver.hpp10
-rw-r--r--src/engine/LADSPANode.cpp76
-rw-r--r--src/engine/LADSPANode.hpp5
-rw-r--r--src/engine/LADSPAPlugin.cpp5
-rw-r--r--src/engine/LV2Node.cpp79
-rw-r--r--src/engine/LV2Node.hpp5
-rw-r--r--src/engine/LV2Plugin.cpp5
-rw-r--r--src/engine/LV2ResizeFeature.hpp1
-rw-r--r--src/engine/NodeBase.cpp81
-rw-r--r--src/engine/NodeBase.hpp28
-rw-r--r--src/engine/NodeImpl.hpp30
-rw-r--r--src/engine/ObjectBuffer.cpp4
-rw-r--r--src/engine/ObjectBuffer.hpp2
-rw-r--r--src/engine/ObjectSender.cpp3
-rw-r--r--src/engine/OutputPort.cpp15
-rw-r--r--src/engine/OutputPort.hpp4
-rw-r--r--src/engine/PatchImpl.cpp56
-rw-r--r--src/engine/PatchImpl.hpp14
-rw-r--r--src/engine/PortImpl.cpp91
-rw-r--r--src/engine/PortImpl.hpp37
-rw-r--r--src/engine/QueuedEngineInterface.cpp2
-rw-r--r--src/engine/events/Connect.cpp25
-rw-r--r--src/engine/events/Connect.hpp4
-rw-r--r--src/engine/events/CreateNode.cpp17
-rw-r--r--src/engine/events/CreateNode.hpp1
-rw-r--r--src/engine/events/CreatePatch.cpp15
-rw-r--r--src/engine/events/CreatePort.cpp10
-rw-r--r--src/engine/events/Delete.cpp24
-rw-r--r--src/engine/events/Disconnect.cpp81
-rw-r--r--src/engine/events/Disconnect.hpp18
-rw-r--r--src/engine/events/DisconnectAll.cpp23
-rw-r--r--src/engine/events/DisconnectAll.hpp10
-rw-r--r--src/engine/events/SetMetadata.cpp108
-rw-r--r--src/engine/events/SetPortValue.cpp2
-rw-r--r--src/engine/internals/Controller.cpp19
-rw-r--r--src/engine/internals/Controller.hpp2
-rw-r--r--src/engine/internals/Note.cpp33
-rw-r--r--src/engine/internals/Note.hpp4
-rw-r--r--src/engine/internals/Trigger.cpp16
-rw-r--r--src/engine/internals/Trigger.hpp2
-rw-r--r--src/engine/tuning.hpp2
60 files changed, 746 insertions, 595 deletions
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(&note_plugin, path, polyphonic, parent, srate, buffer_size)
+NoteNode::NoteNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate)
+ : NodeBase(&note_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