summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-08-11 18:41:31 +0000
committerDavid Robillard <d@drobilla.net>2012-08-11 18:41:31 +0000
commit92600e0011488c66175dea483515daec560cd580 (patch)
tree0df02ad7dd90a59c4abd5c4641fced444a042f09 /src
parent885c186ed6427e7912faadfad7cc91692092efcb (diff)
downloadingen-92600e0011488c66175dea483515daec560cd580.tar.gz
ingen-92600e0011488c66175dea483515daec560cd580.tar.bz2
ingen-92600e0011488c66175dea483515daec560cd580.zip
Considerable DSP performance improvements (mixing overhead, and per-event MIDI overhead with Note/Trigger nodes).
git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4657 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src')
-rw-r--r--src/server/Buffer.cpp12
-rw-r--r--src/server/Buffer.hpp13
-rw-r--r--src/server/CompiledPatch.hpp5
-rw-r--r--src/server/DuplexPort.cpp7
-rw-r--r--src/server/DuplexPort.hpp2
-rw-r--r--src/server/EdgeImpl.cpp74
-rw-r--r--src/server/EdgeImpl.hpp26
-rw-r--r--src/server/InputPort.cpp47
-rw-r--r--src/server/InputPort.hpp3
-rw-r--r--src/server/PatchImpl.cpp18
-rw-r--r--src/server/PortImpl.cpp54
-rw-r--r--src/server/PortImpl.hpp14
-rw-r--r--src/server/events/CreatePatch.cpp2
-rw-r--r--src/server/events/CreatePort.cpp1
-rw-r--r--src/server/events/Delta.cpp9
-rw-r--r--src/server/events/Get.cpp1
-rw-r--r--src/server/events/SetPortValue.hpp5
17 files changed, 120 insertions, 173 deletions
diff --git a/src/server/Buffer.cpp b/src/server/Buffer.cpp
index a91ce1b8..b6b67008 100644
--- a/src/server/Buffer.cpp
+++ b/src/server/Buffer.cpp
@@ -110,18 +110,6 @@ Buffer::copy(const Context& context, const Buffer* src)
}
void
-Buffer::set_block(Sample val, const SampleCount start, const SampleCount end)
-{
- assert(end <= nframes());
-
- // Note: This is done in this particular way so GCC can vectorize it
- Sample* const buf = samples() + start;
- for (SampleCount i = 0; i < (end - start); ++i) {
- buf[i] = val;
- }
-}
-
-void
Buffer::resize(uint32_t capacity)
{
_atom = (LV2_Atom*)realloc(_atom, capacity);
diff --git a/src/server/Buffer.hpp b/src/server/Buffer.hpp
index 720b1073..fd4151b8 100644
--- a/src/server/Buffer.hpp
+++ b/src/server/Buffer.hpp
@@ -46,7 +46,6 @@ public:
void clear();
void resize(uint32_t size);
void copy(const Context& context, const Buffer* src);
- void set_block(Sample val, SampleCount start, SampleCount end);
void prepare_write(Context& context);
void* port_data(PortType port_type);
@@ -104,6 +103,18 @@ public:
return samples()[offset];
}
+ inline void set_block(Sample val,
+ const SampleCount start,
+ const SampleCount end)
+ {
+ assert(end <= nframes());
+ // Note: Do not change this without ensuring GCC can still vectorize it
+ Sample* const buf = samples() + start;
+ for (SampleCount i = 0; i < (end - start); ++i) {
+ buf[i] = val;
+ }
+ }
+
/// Audio buffers only
float peak(const Context& context) const;
diff --git a/src/server/CompiledPatch.hpp b/src/server/CompiledPatch.hpp
index 4fe0c042..203f817b 100644
--- a/src/server/CompiledPatch.hpp
+++ b/src/server/CompiledPatch.hpp
@@ -67,11 +67,6 @@ class CompiledPatch : public std::vector<CompiledNode>
, public Raul::Deletable
, public boost::noncopyable
{
-public:
- typedef std::vector<EdgeImpl*> QueuedEdges;
-
- /** All (audio context => other context) edges */
- std::vector<EdgeImpl*> queued_edges;
};
} // namespace Server
diff --git a/src/server/DuplexPort.cpp b/src/server/DuplexPort.cpp
index c3b1a6b7..c7b81dc8 100644
--- a/src/server/DuplexPort.cpp
+++ b/src/server/DuplexPort.cpp
@@ -21,6 +21,7 @@
#include "Buffer.hpp"
#include "DuplexPort.hpp"
#include "OutputPort.hpp"
+#include "PatchImpl.hpp"
using namespace std;
@@ -60,6 +61,12 @@ DuplexPort::get_buffers(Context& context,
}
}
+uint32_t
+DuplexPort::max_tail_poly(Context& context) const
+{
+ return parent_patch()->internal_poly_process();
+}
+
/** Prepare for the execution of parent patch */
void
DuplexPort::pre_process(Context& context)
diff --git a/src/server/DuplexPort.hpp b/src/server/DuplexPort.hpp
index c12a0b56..5371680d 100644
--- a/src/server/DuplexPort.hpp
+++ b/src/server/DuplexPort.hpp
@@ -53,6 +53,8 @@ public:
virtual ~DuplexPort() {}
+ uint32_t max_tail_poly(Context& context) const;
+
bool get_buffers(Context& context,
BufferFactory& bufs,
Raul::Array<BufferRef>* buffers,
diff --git a/src/server/EdgeImpl.cpp b/src/server/EdgeImpl.cpp
index a88290e8..4a3c5ce9 100644
--- a/src/server/EdgeImpl.cpp
+++ b/src/server/EdgeImpl.cpp
@@ -39,25 +39,11 @@ namespace Server {
EdgeImpl::EdgeImpl(PortImpl* tail, PortImpl* head)
: _tail(tail)
, _head(head)
- , _queue(NULL)
{
assert(tail);
assert(head);
assert(tail != head);
assert(tail->path() != head->path());
-
- if (must_queue())
- _queue = new Raul::RingBuffer(tail->buffer_size() * 2);
-}
-
-void
-EdgeImpl::dump() const
-{
- Raul::debug << _tail->path() << " -> " << _head->path()
- << (must_mix() ? " (MIX) " : " (DIRECT) ")
- << (must_queue() ? " (QUEUE)" : " (NOQUEUE) ")
- << "POLY: " << _tail->poly() << " => " << _head->poly()
- << std::endl;
}
const Raul::Path&
@@ -72,63 +58,10 @@ EdgeImpl::head_path() const
return _head->path();
}
-void
-EdgeImpl::get_sources(Context& context,
- uint32_t voice,
- Buffer** srcs,
- uint32_t max_num_srcs,
- uint32_t& num_srcs)
-{
- if (must_queue() && _queue->read_space() > 0) {
- LV2_Atom obj;
- _queue->peek(sizeof(LV2_Atom), &obj);
- BufferRef buf = context.engine().buffer_factory()->get(
- context, head()->buffer_type(), sizeof(LV2_Atom) + obj.size);
- void* data = buf->port_data(PortType::ATOM);
- _queue->read(sizeof(LV2_Atom) + obj.size, (LV2_Atom*)data);
- srcs[num_srcs++] = buf.get();
- } else if (must_mix()) {
- // Mixing down voices: every src voice mixed into every dst voice
- for (uint32_t v = 0; v < _tail->poly(); ++v) {
- assert(num_srcs < max_num_srcs);
- srcs[num_srcs++] = _tail->buffer(v).get();
- }
- } else {
- // Matching polyphony: each src voice mixed into corresponding dst voice
- assert(_tail->poly() == _head->poly());
- assert(num_srcs < max_num_srcs);
- srcs[num_srcs++] = _tail->buffer(voice).get();
- }
-}
-
-void
-EdgeImpl::queue(Context& context)
-{
- if (!must_queue())
- return;
-
- const Ingen::URIs& uris = _tail->bufs().uris();
-
- BufferRef src_buf = _tail->buffer(0);
- if (src_buf->atom()->type != uris.atom_Sequence) {
- Raul::error << "Queued edge source is not a Sequence" << std::endl;
- return;
- }
-
- LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)src_buf->atom();
- LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
- _queue->write(sizeof(LV2_Atom) + ev->body.size, &ev->body);
- context.engine().message_context().run(
- context, _head->parent_node(), context.start() + ev->time.frames);
-
- }
-}
-
BufferRef
EdgeImpl::buffer(uint32_t voice) const
{
assert(!must_mix());
- assert(!must_queue());
assert(_tail->poly() == 1 || _tail->poly() > voice);
if (_tail->poly() == 1) {
return _tail->buffer(0);
@@ -144,13 +77,6 @@ EdgeImpl::must_mix() const
}
bool
-EdgeImpl::must_queue() const
-{
- return _tail->parent_node()->context()
- != _head->parent_node()->context();
-}
-
-bool
EdgeImpl::can_connect(const OutputPort* src, const InputPort* dst)
{
const Ingen::URIs& uris = src->bufs().uris();
diff --git a/src/server/EdgeImpl.hpp b/src/server/EdgeImpl.hpp
index 23a22ba3..fd5b5ca0 100644
--- a/src/server/EdgeImpl.hpp
+++ b/src/server/EdgeImpl.hpp
@@ -27,7 +27,7 @@
#include "raul/Deletable.hpp"
#include "raul/log.hpp"
-#include "BufferFactory.hpp"
+#include "BufferRef.hpp"
#include "Context.hpp"
namespace Ingen {
@@ -36,8 +36,6 @@ namespace Server {
class PortImpl;
class OutputPort;
class InputPort;
-class Buffer;
-class BufferFactory;
/** Represents a single inbound connection for an InputPort.
*
@@ -60,20 +58,12 @@ class EdgeImpl
public:
EdgeImpl(PortImpl* tail, PortImpl* head);
- PortImpl* tail() const { return _tail; }
- PortImpl* head() const { return _head; }
+ inline PortImpl* tail() const { return _tail; }
+ inline PortImpl* head() const { return _head; }
const Raul::Path& tail_path() const;
const Raul::Path& head_path() const;
- void queue(Context& context);
-
- void get_sources(Context& context,
- uint32_t voice,
- Buffer** srcs,
- uint32_t max_num_srcs,
- uint32_t& num_srcs);
-
/** Get the buffer for a particular voice.
* An Edge is smart - it knows the destination port requesting the
* buffer, and will return accordingly (e.g. the same buffer for every
@@ -84,17 +74,11 @@ public:
/** Whether this edge must mix down voices into a local buffer */
bool must_mix() const;
- /** Whether this edge crosses contexts and must buffer */
- bool must_queue() const;
-
static bool can_connect(const OutputPort* src, const InputPort* dst);
protected:
- void dump() const;
-
- PortImpl* const _tail;
- PortImpl* const _head;
- Raul::RingBuffer* _queue;
+ PortImpl* const _tail;
+ PortImpl* const _head;
};
} // namespace Server
diff --git a/src/server/InputPort.cpp b/src/server/InputPort.cpp
index 48b79822..6ac2eb5e 100644
--- a/src/server/InputPort.cpp
+++ b/src/server/InputPort.cpp
@@ -24,6 +24,7 @@
#include "InputPort.hpp"
#include "NodeImpl.hpp"
#include "OutputPort.hpp"
+#include "PatchImpl.hpp"
#include "ProcessContext.hpp"
#include "ingen/URIs.hpp"
#include "mix.hpp"
@@ -91,8 +92,7 @@ InputPort::get_buffers(Context& context,
} else if (num_edges == 1) {
if (is_process_context) {
- if (!_edges.front().must_mix() &&
- !_edges.front().must_queue()) {
+ if (!_edges.front().must_mix()) {
// Single non-mixing connection, use buffers directly
for (uint32_t v = 0; v < poly; ++v) {
buffers->at(v) = _edges.front().buffer(v);
@@ -156,6 +156,34 @@ InputPort::remove_edge(ProcessContext& context, const OutputPort* tail)
return edge;
}
+uint32_t
+InputPort::max_tail_poly(Context& context) const
+{
+ return parent_node()->parent_patch()->internal_poly_process();
+}
+
+static void
+get_sources(const Context& context,
+ const EdgeImpl& edge,
+ uint32_t voice,
+ const Buffer** srcs,
+ uint32_t max_num_srcs,
+ uint32_t& num_srcs)
+{
+ if (edge.must_mix()) {
+ // Mixing down voices: all tail voices => one head voice
+ for (uint32_t v = 0; v < edge.tail()->poly(); ++v) {
+ assert(num_srcs < max_num_srcs);
+ srcs[num_srcs++] = edge.tail()->buffer(v).get();
+ }
+ } else {
+ // Matching polyphony: each tail voice => corresponding head voice
+ assert(edge.tail()->poly() == edge.head()->poly());
+ assert(num_srcs < max_num_srcs);
+ srcs[num_srcs++] = edge.tail()->buffer(voice).get();
+ }
+}
+
/** Prepare buffer for access, mixing if necessary. Realtime safe.
*/
void
@@ -174,18 +202,18 @@ InputPort::pre_process(Context& context)
_buffers->at(v) = _edges.front().buffer(v);
}
} else {
- uint32_t max_num_srcs = 1;
- for (Edges::const_iterator e = _edges.begin(); e != _edges.end(); ++e) {
- max_num_srcs += e->tail()->poly();
- }
+ const uint32_t src_poly = max_tail_poly(context);
+ const uint32_t max_num_srcs = _edges.size() * src_poly;
- Buffer* srcs[max_num_srcs];
+ const Buffer* srcs[max_num_srcs];
for (uint32_t v = 0; v < _poly; ++v) {
+ // Get all the sources for this voice
uint32_t num_srcs = 0;
for (Edges::iterator e = _edges.begin(); e != _edges.end(); ++e) {
- e->get_sources(context, v, srcs, max_num_srcs, num_srcs);
+ get_sources(context, *e, v, srcs, max_num_srcs, num_srcs);
}
+ // Then mix them into out buffer for this voice
mix(context, buffer(v).get(), srcs, num_srcs);
}
}
@@ -213,8 +241,7 @@ InputPort::direct_connect() const
{
return _edges.size() == 1
&& !_parent->path().is_root()
- && !_edges.front().must_mix()
- && !_edges.front().must_queue();
+ && !_edges.front().must_mix();
}
} // namespace Server
diff --git a/src/server/InputPort.hpp b/src/server/InputPort.hpp
index db614efa..d933344a 100644
--- a/src/server/InputPort.hpp
+++ b/src/server/InputPort.hpp
@@ -67,6 +67,9 @@ public:
boost::intrusive::constant_time_size<false>
> Edges;
+ /** Return the maximum polyphony of an output connected to this input. */
+ virtual uint32_t max_tail_poly(Context& context) const;
+
void add_edge(ProcessContext& context, EdgeImpl* c);
EdgeImpl* remove_edge(ProcessContext& context,
const OutputPort* tail);
diff --git a/src/server/PatchImpl.cpp b/src/server/PatchImpl.cpp
index 9abadadb..d8097568 100644
--- a/src/server/PatchImpl.cpp
+++ b/src/server/PatchImpl.cpp
@@ -21,6 +21,7 @@
#include "ingen/World.hpp"
#include "raul/log.hpp"
+#include "BufferFactory.hpp"
#include "EdgeImpl.hpp"
#include "DuplexPort.hpp"
#include "Engine.hpp"
@@ -52,6 +53,7 @@ PatchImpl::PatchImpl(Engine& engine,
, _process(false)
{
assert(internal_poly >= 1);
+ assert(internal_poly <= 128);
}
PatchImpl::~PatchImpl()
@@ -156,12 +158,6 @@ PatchImpl::process(ProcessContext& context)
for (size_t i = 0; i < _compiled_patch->size(); ++i) {
(*_compiled_patch)[i].node()->process(context);
}
-
- // Queue any cross-context edges
- for (CompiledPatch::QueuedEdges::iterator i = _compiled_patch->queued_edges.begin();
- i != _compiled_patch->queued_edges.end(); ++i) {
- (*i)->queue(context);
- }
}
NodeImpl::post_process(context);
@@ -400,16 +396,6 @@ PatchImpl::compile() const
compile_recursive(node, compiled_patch);
}
- // Add any queued edges that must be run after a cycle
- for (Edges::const_iterator i = _edges.begin();
- i != _edges.end(); ++i) {
- SharedPtr<EdgeImpl> c = PtrCast<EdgeImpl>(i->second);
- if (c->tail()->parent_node()->context() == Context::AUDIO &&
- c->head()->parent_node()->context() == Context::MESSAGE) {
- compiled_patch->queued_edges.push_back(c.get());
- }
- }
-
assert(compiled_patch->size() == _nodes.size());
return compiled_patch;
diff --git a/src/server/PortImpl.cpp b/src/server/PortImpl.cpp
index aee380ff..6a57e6a2 100644
--- a/src/server/PortImpl.cpp
+++ b/src/server/PortImpl.cpp
@@ -135,34 +135,48 @@ PortImpl::cache_properties()
}
void
-PortImpl::set_control_value(Context& context, FrameTime time, Sample value)
+PortImpl::set_control_value(const Context& context,
+ FrameTime time,
+ Sample value)
{
- for (uint32_t v = 0; v < poly(); ++v) {
+ for (uint32_t v = 0; v < _poly; ++v) {
set_voice_value(context, v, time, value);
}
}
void
-PortImpl::set_voice_value(Context& context, uint32_t voice, FrameTime time, Sample value)
+PortImpl::set_voice_value(const Context& context,
+ uint32_t voice,
+ FrameTime time,
+ Sample value)
{
- // Time may be at end so internal nodes can set single sample triggers
- assert(time >= context.start());
- assert(time <= context.start() + context.nframes());
-
- if (_type == PortType::CONTROL) {
- time = context.start();
+ switch (_type.symbol()) {
+ case PortType::CONTROL:
+ buffer(voice)->samples()[0] = value;
+ _set_states->at(voice).state = SetState::SET;
+ break;
+ case PortType::AUDIO:
+ case PortType::CV: {
+ // Time may be at end so internal nodes can set triggers
+ assert(time >= context.start());
+ assert(time <= context.start() + context.nframes());
+
+ const FrameTime offset = time - context.start();
+ if (offset < context.nframes()) {
+ buffer(voice)->set_block(value, offset, context.nframes());
+ }
+ /* else, this is a set at context.nframes(), used to reset a CV port's
+ value for the next block, particularly for triggers on the last
+ frame of a block (set nframes-1 to 1, then nframes to 0). */
+
+ SetState& state = _set_states->at(voice);
+ state.state = (offset == 0) ? SetState::SET : SetState::HALF_SET_CYCLE_1;
+ state.time = time;
+ state.value = value;
+ }
+ default:
+ break;
}
-
- FrameTime offset = time - context.start();
- FrameTime end = (_type == PortType::CONTROL) ? 1 : context.nframes();
- if (offset < context.nframes()) {
- buffer(voice)->set_block(value, offset, end);
- } // else trigger at very end of block, and set to 0 at start of next block
-
- SetState& state = _set_states->at(voice);
- state.state = (offset == 0) ? SetState::SET : SetState::HALF_SET_CYCLE_1;
- state.time = time;
- state.value = value;
}
void
diff --git a/src/server/PortImpl.hpp b/src/server/PortImpl.hpp
index 0a8415f7..e55448f5 100644
--- a/src/server/PortImpl.hpp
+++ b/src/server/PortImpl.hpp
@@ -99,12 +99,14 @@ public:
void update_set_state(Context& context, uint32_t voice);
- void set_voice_value(Context& context,
- uint32_t voice,
- FrameTime time,
- Sample value);
-
- void set_control_value(Context& context, FrameTime time, Sample value);
+ void set_voice_value(const Context& context,
+ uint32_t voice,
+ FrameTime time,
+ Sample value);
+
+ void set_control_value(const Context& context,
+ FrameTime time,
+ Sample value);
/** Called once per process cycle */
virtual void pre_process(Context& context) = 0;
diff --git a/src/server/events/CreatePatch.cpp b/src/server/events/CreatePatch.cpp
index 476ccccb..b29ca667 100644
--- a/src/server/events/CreatePatch.cpp
+++ b/src/server/events/CreatePatch.cpp
@@ -69,7 +69,7 @@ CreatePatch::pre_process()
int_poly = p->second.get_int32();
}
- if (int_poly < 1) {
+ if (int_poly < 1 || int_poly > 128) {
return Event::pre_process_done(INVALID_POLY, path);
}
diff --git a/src/server/events/CreatePort.cpp b/src/server/events/CreatePort.cpp
index c62e858c..c156c13a 100644
--- a/src/server/events/CreatePort.cpp
+++ b/src/server/events/CreatePort.cpp
@@ -23,6 +23,7 @@
#include "raul/Path.hpp"
#include "Broadcaster.hpp"
+#include "BufferFactory.hpp"
#include "CreatePort.hpp"
#include "Driver.hpp"
#include "DuplexPort.hpp"
diff --git a/src/server/events/Delta.cpp b/src/server/events/Delta.cpp
index b1408d7a..f5d5239a 100644
--- a/src/server/events/Delta.cpp
+++ b/src/server/events/Delta.cpp
@@ -206,8 +206,13 @@ Delta::pre_process()
}
} else if (key == uris.ingen_polyphony) {
if (value.type() == uris.forge.Int) {
- op = POLYPHONY;
- _patch->prepare_internal_poly(*_engine.buffer_factory(), value.get_int32());
+ if (value.get_int32() < 1 || value.get_int32() > 128) {
+ _status == INVALID_POLY;
+ } else {
+ op = POLYPHONY;
+ _patch->prepare_internal_poly(
+ *_engine.buffer_factory(), value.get_int32());
+ }
} else {
_status = BAD_VALUE_TYPE;
}
diff --git a/src/server/events/Get.cpp b/src/server/events/Get.cpp
index ae4174bb..8ffe9319 100644
--- a/src/server/events/Get.cpp
+++ b/src/server/events/Get.cpp
@@ -19,6 +19,7 @@
#include "ingen/Interface.hpp"
#include "Broadcaster.hpp"
+#include "BufferFactory.hpp"
#include "Driver.hpp"
#include "Engine.hpp"
#include "EngineStore.hpp"
diff --git a/src/server/events/SetPortValue.hpp b/src/server/events/SetPortValue.hpp
index 93a4b528..a82553f5 100644
--- a/src/server/events/SetPortValue.hpp
+++ b/src/server/events/SetPortValue.hpp
@@ -32,11 +32,6 @@ namespace Events {
/** An event to change the value of a port.
*
- * This event can either be queued or immediate, depending on the queued
- * parameter passed to the constructor. It must be passed to the appropriate
- * place (ie queued event passed to the event queue and non-queued event
- * processed in the audio thread) or nasty things will happen.
- *
* \ingroup engine
*/
class SetPortValue : public Event