summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/engine/AudioBuffer.cpp15
-rw-r--r--src/engine/Buffer.hpp4
-rw-r--r--src/engine/Context.hpp24
-rw-r--r--src/engine/ControlBindings.cpp1
-rw-r--r--src/engine/EventBuffer.cpp3
-rw-r--r--src/engine/EventBuffer.hpp4
-rw-r--r--src/engine/InputPort.cpp5
-rw-r--r--src/engine/InternalPlugin.cpp11
-rw-r--r--src/engine/JackDriver.cpp23
-rw-r--r--src/engine/LADSPANode.cpp7
-rw-r--r--src/engine/LADSPANode.hpp3
-rw-r--r--src/engine/LV2Node.cpp7
-rw-r--r--src/engine/LV2Node.hpp3
-rw-r--r--src/engine/NodeBase.cpp11
-rw-r--r--src/engine/NodeBase.hpp3
-rw-r--r--src/engine/NodeFactory.cpp12
-rw-r--r--src/engine/NodeImpl.hpp4
-rw-r--r--src/engine/ObjectBuffer.cpp18
-rw-r--r--src/engine/ObjectBuffer.hpp4
-rw-r--r--src/engine/PatchImpl.cpp4
-rw-r--r--src/engine/PatchImpl.hpp2
-rw-r--r--src/engine/PluginImpl.cpp3
-rw-r--r--src/engine/PortImpl.cpp4
-rw-r--r--src/engine/PortImpl.hpp2
-rw-r--r--src/engine/ProcessContext.hpp13
-rw-r--r--src/engine/ProcessSlave.hpp2
-rw-r--r--src/engine/events/SetMetadata.cpp4
-rw-r--r--src/engine/internals/Delay.cpp208
-rw-r--r--src/engine/internals/Delay.hpp79
-rw-r--r--src/engine/internals/Note.cpp5
-rw-r--r--src/engine/wscript1
31 files changed, 414 insertions, 75 deletions
diff --git a/src/engine/AudioBuffer.cpp b/src/engine/AudioBuffer.cpp
index 99d97e14..145df559 100644
--- a/src/engine/AudioBuffer.cpp
+++ b/src/engine/AudioBuffer.cpp
@@ -170,10 +170,23 @@ AudioBuffer::copy(Context& context, const Buffer* src)
return;
}
- // Control => Control or Audio => Audio
+ // Control => Control
if (src_abuf->is_control() == is_control()) {
ObjectBuffer::copy(context, src);
+ // Audio => Audio
+ } else if (!src_abuf->is_control() && !is_control()) {
+ copy(src_abuf->data(),
+ context.offset(), context.offset() + context.nframes() - 1);
+
+ // Audio => Control
+ } else if (!src_abuf->is_control() && is_control()) {
+ data()[0] = src_abuf->data()[context.offset()];
+
+ // Control => Audio
+ } else if (src_abuf->is_control() && !is_control()) {
+ data()[context.offset()] = src_abuf->data()[0];
+
// Control => Audio or Audio => Control
} else {
set_block(src_abuf->data()[0], 0, nframes());
diff --git a/src/engine/Buffer.hpp b/src/engine/Buffer.hpp
index 0a9d59c2..1997c1cb 100644
--- a/src/engine/Buffer.hpp
+++ b/src/engine/Buffer.hpp
@@ -50,8 +50,8 @@ public:
virtual void resize(size_t size) { _size = size; }
- virtual void* port_data(Shared::PortType port_type) = 0;
- virtual const void* port_data(Shared::PortType port_type) const = 0;
+ virtual void* port_data(Shared::PortType port_type, SampleCount offset=0) = 0;
+ virtual const void* port_data(Shared::PortType port_type, SampleCount offset=0) const = 0;
/** Rewind (ie reset read pointer), but leave contents unchanged */
virtual void rewind() const {}
diff --git a/src/engine/Context.hpp b/src/engine/Context.hpp
index e0bc924e..a30706da 100644
--- a/src/engine/Context.hpp
+++ b/src/engine/Context.hpp
@@ -38,6 +38,9 @@ public:
, _engine(engine)
, _event_sink(engine, event_queue_size)
, _start(0)
+ , _nframes(0)
+ , _end(0)
+ , _offset(0)
, _realtime(true)
{}
@@ -45,11 +48,14 @@ public:
ID id() const { return _id; }
- void locate(FrameTime s) { _start = s; }
+ void locate(FrameTime s, SampleCount o=0) { _start = s; _offset=o; }
- inline Engine& engine() const { return _engine; }
- inline FrameTime start() const { return _start; }
- inline bool realtime() const { return _realtime; }
+ inline Engine& engine() const { return _engine; }
+ inline FrameTime start() const { return _start; }
+ inline SampleCount nframes() const { return _nframes; }
+ inline FrameTime end() const { return _end; }
+ inline SampleCount offset() const { return _offset; }
+ inline bool realtime() const { return _realtime; }
inline const EventSink& event_sink() const { return _event_sink; }
inline EventSink& event_sink() { return _event_sink; }
@@ -58,10 +64,12 @@ protected:
ID _id; ///< Fast ID for this context
Engine& _engine; ///< Engine we're running in
-private:
- EventSink _event_sink; ///< Sink for events generated in a realtime context
- FrameTime _start; ///< Start frame of this cycle, timeline relative
- bool _realtime; ///< True iff context is hard realtime
+ EventSink _event_sink; ///< Sink for events generated in a realtime context
+ FrameTime _start; ///< Start frame of this cycle, timeline relative
+ SampleCount _nframes; ///< Length of this cycle in frames
+ FrameTime _end; ///< End frame of this cycle, timeline relative
+ SampleCount _offset; ///< Start offset relative to start of driver buffers
+ bool _realtime; ///< True iff context is hard realtime
};
diff --git a/src/engine/ControlBindings.cpp b/src/engine/ControlBindings.cpp
index e183404a..ead1e6ea 100644
--- a/src/engine/ControlBindings.cpp
+++ b/src/engine/ControlBindings.cpp
@@ -18,7 +18,6 @@
#include <math.h>
#include "raul/log.hpp"
#include "raul/midi_events.h"
-#include "raul/IntrusivePtr.hpp"
#include "events/SendPortValue.hpp"
#include "events/SendBinding.hpp"
#include "AudioBuffer.hpp"
diff --git a/src/engine/EventBuffer.cpp b/src/engine/EventBuffer.cpp
index 2ba74937..6ec3f259 100644
--- a/src/engine/EventBuffer.cpp
+++ b/src/engine/EventBuffer.cpp
@@ -83,7 +83,8 @@ EventBuffer::prepare_read(Context& context)
void
EventBuffer::prepare_write(Context& context)
{
- clear();
+ if (context.offset() == 0)
+ clear();
}
diff --git a/src/engine/EventBuffer.hpp b/src/engine/EventBuffer.hpp
index 2007cdf1..6964d63c 100644
--- a/src/engine/EventBuffer.hpp
+++ b/src/engine/EventBuffer.hpp
@@ -32,8 +32,8 @@ public:
EventBuffer(BufferFactory& bufs, size_t capacity);
~EventBuffer();
- void* port_data(Shared::PortType port_type) { return _data; }
- const void* port_data(Shared::PortType port_type) const { return _data; }
+ void* port_data(Shared::PortType port_type, SampleCount offset=0) { return _data; }
+ const void* port_data(Shared::PortType port_type, SampleCount offset=0) const { return _data; }
inline void rewind() const { lv2_event_begin(&_iter, _data); }
diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp
index f4fd3620..fa45117d 100644
--- a/src/engine/InputPort.cpp
+++ b/src/engine/InputPort.cpp
@@ -217,11 +217,6 @@ InputPort::pre_process(Context& context)
void
InputPort::post_process(Context& context)
{
- // Prepare buffers for next cycle
- if (type() != PortType::CONTROL && num_connections() > 1)
- for (uint32_t v = 0; v < _poly; ++v)
- buffer(v)->prepare_write(context);
-
_set_by_user = false;
}
diff --git a/src/engine/InternalPlugin.cpp b/src/engine/InternalPlugin.cpp
index b4b0be8b..802ec955 100644
--- a/src/engine/InternalPlugin.cpp
+++ b/src/engine/InternalPlugin.cpp
@@ -17,9 +17,10 @@
#include <cassert>
#include "shared/LV2URIMap.hpp"
+#include "internals/Controller.hpp"
+#include "internals/Delay.hpp"
#include "internals/Note.hpp"
#include "internals/Trigger.hpp"
-#include "internals/Controller.hpp"
#include "Driver.hpp"
#include "Engine.hpp"
#include "InternalPlugin.hpp"
@@ -52,12 +53,14 @@ InternalPlugin::instantiate(BufferFactory& bufs,
const SampleCount srate = engine.driver()->sample_rate();
const string uri_str = uri().str();
- if (uri_str == NS_INTERNALS "Note") {
+ if (uri_str == NS_INTERNALS "Controller") {
+ return new ControllerNode(bufs, name, polyphonic, parent, srate);
+ } else if (uri_str == NS_INTERNALS "Delay") {
+ return new DelayNode(bufs, name, polyphonic, parent, srate);
+ } else if (uri_str == NS_INTERNALS "Note") {
return new NoteNode(bufs, name, polyphonic, parent, srate);
} else if (uri_str == NS_INTERNALS "Trigger") {
return new TriggerNode(bufs, name, polyphonic, parent, srate);
- } else if (uri_str == NS_INTERNALS "Controller") {
- return new ControllerNode(bufs, name, polyphonic, parent, srate);
} else {
return NULL;
}
diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp
index 18426bf4..78b14121 100644
--- a/src/engine/JackDriver.cpp
+++ b/src/engine/JackDriver.cpp
@@ -417,11 +417,11 @@ JackDriver::_process_cb(jack_nframes_t nframes)
_transport_state = jack_transport_query(_client, &_position);
- _process_context.set_time_slice(nframes, start_of_current_cycle, end_of_current_cycle);
+ _process_context.set_time_slice(nframes, 0, start_of_current_cycle, end_of_current_cycle);
for (Engine::ProcessSlaves::iterator i = _engine.process_slaves().begin();
i != _engine.process_slaves().end(); ++i) {
- (*i)->context().set_time_slice(nframes, start_of_current_cycle, end_of_current_cycle);
+ (*i)->context().set_time_slice(nframes, 0, start_of_current_cycle, end_of_current_cycle);
}
// Read input
@@ -432,13 +432,29 @@ JackDriver::_process_cb(jack_nframes_t nframes)
_engine.control_bindings()->pre_process(_process_context,
PtrCast<EventBuffer>(_root_patch->port_impl(0)->buffer(0)).get());
+ _engine.post_processor()->set_end_time(_process_context.end());
+
// Process events that came in during the last cycle
// (Aiming for jitter-free 1 block event latency, ideally)
_engine.process_events(_process_context);
// Run root patch
- if (_root_patch)
+ if (_root_patch) {
_root_patch->process(_process_context);
+#if 0
+ const FrameTime cycle_start = _process_context.start();
+ static const SampleCount control_block_size = nframes / 2;
+ for (jack_nframes_t i = 0; i < nframes; i += control_block_size) {
+ const SampleCount block_size = (i + control_block_size < nframes)
+ ? control_block_size
+ : nframes - i;
+ _process_context.set_time_slice(block_size, i,
+ cycle_start + i,
+ cycle_start + i + block_size);
+ _root_patch->process(_process_context);
+ }
+#endif
+ }
// Emit control binding feedback
_engine.control_bindings()->post_process(_process_context,
@@ -452,7 +468,6 @@ JackDriver::_process_cb(jack_nframes_t nframes)
for (Raul::List<JackPort*>::iterator i = _ports.begin(); i != _ports.end(); ++i)
(*i)->post_process(_process_context);
- _engine.post_processor()->set_end_time(_process_context.end());
return 0;
}
diff --git a/src/engine/LADSPANode.cpp b/src/engine/LADSPANode.cpp
index 80e69162..66472f6a 100644
--- a/src/engine/LADSPANode.cpp
+++ b/src/engine/LADSPANode.cpp
@@ -275,12 +275,13 @@ LADSPANode::process(ProcessContext& context)
void
-LADSPANode::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf)
+LADSPANode::set_port_buffer(uint32_t voice, uint32_t port_num,
+ IntrusivePtr<Buffer> buf, SampleCount offset)
{
- NodeBase::set_port_buffer(voice, port_num, buf);
+ NodeBase::set_port_buffer(voice, port_num, buf, offset);
_descriptor->connect_port(instance(voice), port_num,
- buf ? (LADSPA_Data*)buf->port_data(_ports->at(port_num)->type()) : NULL);
+ buf ? (LADSPA_Data*)buf->port_data(_ports->at(port_num)->type(), offset) : NULL);
}
diff --git a/src/engine/LADSPANode.hpp b/src/engine/LADSPANode.hpp
index 927e6255..ad2073c6 100644
--- a/src/engine/LADSPANode.hpp
+++ b/src/engine/LADSPANode.hpp
@@ -55,7 +55,8 @@ public:
void process(ProcessContext& context);
- void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf);
+ void set_port_buffer(uint32_t voice, uint32_t port_num,
+ IntrusivePtr<Buffer> buf, SampleCount offset);
protected:
inline LADSPA_Handle instance(uint32_t voice) { return (*_instances)[voice]->handle; }
diff --git a/src/engine/LV2Node.cpp b/src/engine/LV2Node.cpp
index 65da2c2c..a8892925 100644
--- a/src/engine/LV2Node.cpp
+++ b/src/engine/LV2Node.cpp
@@ -392,11 +392,12 @@ LV2Node::process(ProcessContext& context)
void
-LV2Node::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf)
+LV2Node::set_port_buffer(uint32_t voice, uint32_t port_num,
+ IntrusivePtr<Buffer> buf, SampleCount offset)
{
- NodeBase::set_port_buffer(voice, port_num, buf);
+ NodeBase::set_port_buffer(voice, port_num, buf, offset);
slv2_instance_connect_port(instance(voice), port_num,
- buf ? buf->port_data(_ports->at(port_num)->type()) : NULL);
+ buf ? buf->port_data(_ports->at(port_num)->type(), offset) : NULL);
}
diff --git a/src/engine/LV2Node.hpp b/src/engine/LV2Node.hpp
index 4d751f32..8b7a7bc3 100644
--- a/src/engine/LV2Node.hpp
+++ b/src/engine/LV2Node.hpp
@@ -58,7 +58,8 @@ public:
void process(ProcessContext& context);
- void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf);
+ void set_port_buffer(uint32_t voice, uint32_t port_num,
+ IntrusivePtr<Buffer> buf, SampleCount offset);
protected:
inline SLV2Instance instance(uint32_t voice) { return (SLV2Instance)(*_instances)[voice].get(); }
diff --git a/src/engine/NodeBase.cpp b/src/engine/NodeBase.cpp
index ca9103da..967f7d3c 100644
--- a/src/engine/NodeBase.cpp
+++ b/src/engine/NodeBase.cpp
@@ -216,8 +216,10 @@ NodeBase::pre_process(Context& context)
// Mix down input ports
for (uint32_t i = 0; i < num_ports(); ++i) {
PortImpl* const port = _ports->at(i);
- if (port->context() == Context::AUDIO)
+ if (port->context() == Context::AUDIO) {
port->pre_process(context);
+ port->connect_buffers(context.offset());
+ }
}
}
@@ -266,10 +268,11 @@ NodeBase::reset_valid_ports()
void
-NodeBase::set_port_buffer(uint32_t voice, uint32_t port_num, BufferFactory::Ref buf)
+NodeBase::set_port_buffer(uint32_t voice, uint32_t port_num,
+ BufferFactory::Ref buf, SampleCount offset)
{
- /*debug << path() << " set port " << port_num << " voice " << voice
- << " buffer " << buf << endl;*/
+ /*std::cout << path() << " set port " << port_num << " voice " << voice
+ << " buffer " << buf << " offset " << offset << std::endl;*/
}
diff --git a/src/engine/NodeBase.hpp b/src/engine/NodeBase.hpp
index 4b5e5a19..baab7f50 100644
--- a/src/engine/NodeBase.hpp
+++ b/src/engine/NodeBase.hpp
@@ -91,7 +91,8 @@ 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, SampleCount offset);
virtual void set_buffer_size(Context& context, BufferFactory& bufs,
Shared::PortType type, size_t size);
diff --git a/src/engine/NodeFactory.cpp b/src/engine/NodeFactory.cpp
index 28920d3c..87b54d81 100644
--- a/src/engine/NodeFactory.cpp
+++ b/src/engine/NodeFactory.cpp
@@ -25,9 +25,10 @@
#include "raul/Atom.hpp"
#include "ingen-config.h"
#include "module/World.hpp"
+#include "internals/Controller.hpp"
+#include "internals/Delay.hpp"
#include "internals/Note.hpp"
#include "internals/Trigger.hpp"
-#include "internals/Controller.hpp"
#include "Engine.hpp"
#include "InternalPlugin.hpp"
#include "NodeFactory.hpp"
@@ -137,14 +138,17 @@ NodeFactory::load_plugins()
void
NodeFactory::load_internal_plugins()
{
+ InternalPlugin& controller_plug = ControllerNode::internal_plugin();
+ _plugins.insert(make_pair(controller_plug.uri(), &controller_plug));
+
+ InternalPlugin& delay_plug = DelayNode::internal_plugin();
+ _plugins.insert(make_pair(delay_plug.uri(), &delay_plug));
+
InternalPlugin& note_plug = NoteNode::internal_plugin();
_plugins.insert(make_pair(note_plug.uri(), &note_plug));
InternalPlugin& trigger_plug = TriggerNode::internal_plugin();
_plugins.insert(make_pair(trigger_plug.uri(), &trigger_plug));
-
- InternalPlugin& controller_plug = ControllerNode::internal_plugin();
- _plugins.insert(make_pair(controller_plug.uri(), &controller_plug));
}
diff --git a/src/engine/NodeImpl.hpp b/src/engine/NodeImpl.hpp
index 05b51b83..97724bfb 100644
--- a/src/engine/NodeImpl.hpp
+++ b/src/engine/NodeImpl.hpp
@@ -22,6 +22,7 @@
#include "raul/IntrusivePtr.hpp"
#include "interface/Node.hpp"
#include "GraphObjectImpl.hpp"
+#include "types.hpp"
namespace Raul { template <typename T> class List; class Maid; }
@@ -118,7 +119,8 @@ public:
*/
virtual void process(ProcessContext& context) = 0;
- virtual void set_port_buffer(uint32_t voice, uint32_t port_num, IntrusivePtr<Buffer> buf) = 0;
+ virtual void set_port_buffer(uint32_t voice, uint32_t port_num,
+ IntrusivePtr<Buffer> buf, SampleCount offset) = 0;
virtual uint32_t num_ports() const = 0;
diff --git a/src/engine/ObjectBuffer.cpp b/src/engine/ObjectBuffer.cpp
index c905826d..5a3462cc 100644
--- a/src/engine/ObjectBuffer.cpp
+++ b/src/engine/ObjectBuffer.cpp
@@ -102,7 +102,7 @@ ObjectBuffer::resize(size_t size)
void*
-ObjectBuffer::port_data(PortType port_type)
+ObjectBuffer::port_data(PortType port_type, SampleCount offset)
{
switch (port_type.symbol()) {
case PortType::CONTROL:
@@ -111,7 +111,7 @@ ObjectBuffer::port_data(PortType port_type)
case PortType::CONTROL:
return (float*)object()->body;
case PortType::AUDIO:
- return ((LV2_Vector_Body*)object()->body)->elems;
+ return (float*)((LV2_Vector_Body*)object()->body)->elems + offset;
default:
warn << "Audio data requested from non-audio buffer" << endl;
return NULL;
@@ -124,13 +124,21 @@ ObjectBuffer::port_data(PortType port_type)
const void*
-ObjectBuffer::port_data(PortType port_type) const
+ObjectBuffer::port_data(PortType port_type, SampleCount offset) const
{
switch (port_type.symbol()) {
case PortType::CONTROL:
- return _buf + sizeof(LV2_Object);
case PortType::AUDIO:
- return _buf + sizeof(LV2_Object) + sizeof(LV2_Vector_Body);
+ switch (_type.symbol()) {
+ case PortType::CONTROL:
+ return (float*)object()->body;
+ case PortType::AUDIO:
+ return (float*)((LV2_Vector_Body*)object()->body)->elems + offset;
+ default:
+ warn << "Audio data requested from non-audio buffer" << endl;
+ return NULL;
+ }
+ break;
default:
return _buf;
}
diff --git a/src/engine/ObjectBuffer.hpp b/src/engine/ObjectBuffer.hpp
index 7d6d08e1..7cea89fc 100644
--- a/src/engine/ObjectBuffer.hpp
+++ b/src/engine/ObjectBuffer.hpp
@@ -34,8 +34,8 @@ public:
void clear();
- void* port_data(Shared::PortType port_type);
- const void* port_data(Shared::PortType port_type) const;
+ void* port_data(Shared::PortType port_type, SampleCount offset);
+ const void* port_data(Shared::PortType port_type, SampleCount offset) const;
void prepare_write(Context& context);
diff --git a/src/engine/PatchImpl.cpp b/src/engine/PatchImpl.cpp
index 77408275..a7b9c699 100644
--- a/src/engine/PatchImpl.cpp
+++ b/src/engine/PatchImpl.cpp
@@ -119,7 +119,7 @@ PatchImpl::prepare_internal_poly(BufferFactory& bufs, uint32_t poly)
bool
-PatchImpl::apply_internal_poly(BufferFactory& bufs, Raul::Maid& maid, uint32_t poly)
+PatchImpl::apply_internal_poly(ProcessContext& context, BufferFactory& bufs, Raul::Maid& maid, uint32_t poly)
{
ThreadManager::assert_thread(THREAD_PROCESS);
@@ -136,7 +136,7 @@ PatchImpl::apply_internal_poly(BufferFactory& bufs, Raul::Maid& maid, uint32_t p
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();
+ port->connect_buffers(context.offset());
}
}
diff --git a/src/engine/PatchImpl.hpp b/src/engine/PatchImpl.hpp
index c051f76b..a8392aca 100644
--- a/src/engine/PatchImpl.hpp
+++ b/src/engine/PatchImpl.hpp
@@ -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(BufferFactory& bufs, Raul::Maid& maid, uint32_t poly);
+ bool apply_internal_poly(ProcessContext& context, BufferFactory& bufs, Raul::Maid& maid, uint32_t poly);
// Patch specific stuff not inherited from Node
diff --git a/src/engine/PluginImpl.cpp b/src/engine/PluginImpl.cpp
index 4aa38032..1578ec34 100644
--- a/src/engine/PluginImpl.cpp
+++ b/src/engine/PluginImpl.cpp
@@ -17,9 +17,6 @@
#include "raul/log.hpp"
#include "PluginImpl.hpp"
-#include "internals/Note.hpp"
-#include "internals/Trigger.hpp"
-#include "internals/Controller.hpp"
using namespace std;
using namespace Raul;
diff --git a/src/engine/PortImpl.cpp b/src/engine/PortImpl.cpp
index dac3fef0..1f2c6530 100644
--- a/src/engine/PortImpl.cpp
+++ b/src/engine/PortImpl.cpp
@@ -172,10 +172,10 @@ PortImpl::set_buffer_size(Context& context, BufferFactory& bufs, size_t size)
void
-PortImpl::connect_buffers()
+PortImpl::connect_buffers(SampleCount offset)
{
for (uint32_t v = 0; v < _poly; ++v)
- PortImpl::parent_node()->set_port_buffer(v, _index, buffer(v));
+ PortImpl::parent_node()->set_port_buffer(v, _index, buffer(v), offset);
}
diff --git a/src/engine/PortImpl.hpp b/src/engine/PortImpl.hpp
index ee61b367..6771b78a 100644
--- a/src/engine/PortImpl.hpp
+++ b/src/engine/PortImpl.hpp
@@ -97,7 +97,7 @@ public:
get_buffers(bufs, _buffers, poly);
}
- virtual void connect_buffers();
+ virtual void connect_buffers(SampleCount offset=0);
virtual void recycle_buffers();
virtual bool is_input() const = 0;
diff --git a/src/engine/ProcessContext.hpp b/src/engine/ProcessContext.hpp
index 068b0c85..fa8e3910 100644
--- a/src/engine/ProcessContext.hpp
+++ b/src/engine/ProcessContext.hpp
@@ -42,22 +42,13 @@ class ProcessContext : public Context
public:
ProcessContext(Engine& engine)
: Context(engine, AUDIO)
- , _nframes(0)
- , _end(0)
{}
- void set_time_slice(SampleCount nframes, FrameTime start, FrameTime end) {
- locate(start);
+ void set_time_slice(SampleCount nframes, SampleCount offset, FrameTime start, FrameTime end) {
+ locate(start, offset);
_nframes = nframes;
_end = end;
}
-
- inline SampleCount nframes() const { return _nframes; }
- inline FrameTime end() const { return _end; }
-
-private:
- SampleCount _nframes; ///< Length of this cycle in frames
- FrameTime _end; ///< End frame of this cycle, timeline relative
};
diff --git a/src/engine/ProcessSlave.hpp b/src/engine/ProcessSlave.hpp
index eb876cfb..f6efcb8e 100644
--- a/src/engine/ProcessSlave.hpp
+++ b/src/engine/ProcessSlave.hpp
@@ -59,7 +59,7 @@ public:
_index = start_index;
_state = STATE_RUNNING;
_compiled_patch = compiled_patch;
- _process_context.set_time_slice(context.nframes(), context.start(), context.end());
+ _process_context.set_time_slice(context.nframes(), context.offset(), context.start(), context.end());
Raul::Slave::whip();
}
diff --git a/src/engine/events/SetMetadata.cpp b/src/engine/events/SetMetadata.cpp
index fefc7835..4de74eac 100644
--- a/src/engine/events/SetMetadata.cpp
+++ b/src/engine/events/SetMetadata.cpp
@@ -26,6 +26,7 @@
#include "CreateNode.hpp"
#include "CreatePatch.hpp"
#include "CreatePort.hpp"
+#include "Driver.hpp"
#include "Engine.hpp"
#include "EngineStore.hpp"
#include "GraphObjectImpl.hpp"
@@ -312,7 +313,8 @@ SetMetadata::execute(ProcessContext& context)
break;
case POLYPHONY:
if (_patch->internal_poly() != static_cast<uint32_t>(value.get_int32()) &&
- !_patch->apply_internal_poly(*_engine.buffer_factory(),
+ !_patch->apply_internal_poly(_engine.driver()->context(),
+ *_engine.buffer_factory(),
*_engine.maid(), value.get_int32())) {
_error = INTERNAL;
}
diff --git a/src/engine/internals/Delay.cpp b/src/engine/internals/Delay.cpp
new file mode 100644
index 00000000..202ba616
--- /dev/null
+++ b/src/engine/internals/Delay.cpp
@@ -0,0 +1,208 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007-2009 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cmath>
+#include <limits.h>
+#include "raul/log.hpp"
+#include "raul/Array.hpp"
+#include "raul/Maid.hpp"
+#include "raul/midi_events.h"
+#include "shared/LV2URIMap.hpp"
+#include "internals/Delay.hpp"
+#include "AudioBuffer.hpp"
+#include "Driver.hpp"
+#include "EventBuffer.hpp"
+#include "InputPort.hpp"
+#include "InternalPlugin.hpp"
+#include "OutputPort.hpp"
+#include "PatchImpl.hpp"
+#include "ProcessContext.hpp"
+#include "ingen-config.h"
+#include "util.hpp"
+
+#define LOG(s) s << "[DelayNode] "
+
+#define CALC_DELAY(delaytime) \
+ (f_clamp (delaytime * (float)sample_rate, 1.0f, (float)(buffer_mask + 1)))
+
+using namespace std;
+using namespace Raul;
+
+namespace Ingen {
+namespace Internals {
+
+using namespace Shared;
+
+static const float MAX_DELAY_SECONDS = 8.0f;
+
+static InternalPlugin note_plugin(NS_INTERNALS "Delay", "delay");
+
+InternalPlugin& DelayNode::internal_plugin() { return note_plugin; }
+
+DelayNode::DelayNode(BufferFactory& bufs, const string& path, bool polyphonic, PatchImpl* parent, SampleRate srate)
+ : NodeBase(&note_plugin, path, polyphonic, parent, srate)
+ , _buffer(0)
+ , _buffer_length(0)
+ , _buffer_mask(0)
+ , _write_phase(0)
+{
+ const LV2URIMap& uris = Shared::LV2URIMap::instance();
+ _ports = new Raul::Array<PortImpl*>(3);
+
+ const float default_delay = 1.0f;
+ _last_delay_time = default_delay;
+ _delay_samples = default_delay;
+
+ _delay_port = new InputPort(bufs, this, "delay", 1, _polyphony, PortType::CONTROL, default_delay);
+ _delay_port->set_property(uris.lv2_name, "Delay");
+ _delay_port->set_property(uris.lv2_default, default_delay);
+ _delay_port->set_property(uris.lv2_minimum, (float)(1.0/(double)srate));
+ _delay_port->set_property(uris.lv2_maximum, MAX_DELAY_SECONDS);
+ _ports->at(0) = _delay_port;
+
+ _in_port = new InputPort(bufs, this, "in", 0, 1, PortType::AUDIO, 0.0f);
+ _in_port->set_property(uris.lv2_name, "Input");
+ _ports->at(1) = _in_port;
+
+ _out_port = new OutputPort(bufs, this, "out", 0, 1, PortType::AUDIO, 0.0f);
+ _out_port->set_property(uris.lv2_name, "Output");
+ _ports->at(2) = _out_port;
+
+ //_buffer = bufs.get(PortType::AUDIO, bufs.audio_buffer_size(buffer_length_frames), true);
+
+}
+
+
+DelayNode::~DelayNode()
+{
+ //_buffer.reset();
+ free(_buffer);
+}
+
+
+void
+DelayNode::activate(BufferFactory& bufs)
+{
+ NodeBase::activate(bufs);
+ const SampleCount min_size = MAX_DELAY_SECONDS * _srate;
+
+ // Smallest power of two larger than min_size
+ SampleCount size = 1;
+ while (size < min_size)
+ size <<= 1;
+
+ _buffer = (float*)calloc(size, sizeof(float));
+ _buffer_mask = size - 1;
+ _buffer_length = size;
+ //_buffer->clear();
+ _write_phase = 0;
+}
+
+
+static inline float f_clamp(float x, float a, float b)
+{
+ const float x1 = fabs(x - a);
+ const float x2 = fabs(x - b);
+
+ x = x1 + a + b;
+ x -= x2;
+ x *= 0.5;
+
+ return x;
+}
+
+
+static inline float cube_interp(const float fr, const float inm1, const float
+ in, const float inp1, const float inp2)
+{
+ return in + 0.5f * fr * (inp1 - inm1 +
+ fr * (4.0f * inp1 + 2.0f * inm1 - 5.0f * in - inp2 +
+ fr * (3.0f * (in - inp1) - inm1 + inp2)));
+}
+
+
+void
+DelayNode::process(ProcessContext& context)
+{
+ AudioBuffer* const delay_buf = (AudioBuffer*)_delay_port->buffer(0).get();
+ AudioBuffer* const in_buf = (AudioBuffer*)_in_port->buffer(0).get();
+ AudioBuffer* const out_buf = (AudioBuffer*)_out_port->buffer(0).get();
+
+ NodeBase::pre_process(context);
+
+ DelayNode* plugin_data = this;
+
+ const float* const in = in_buf->data();
+ float* const out = out_buf->data();
+ const float delay_time = delay_buf->data()[0];
+ const uint32_t buffer_mask = plugin_data->_buffer_mask;
+ const unsigned int sample_rate = plugin_data->_srate;
+ float delay_samples = plugin_data->_delay_samples;
+ long write_phase = plugin_data->_write_phase;
+ const uint32_t sample_count = context.nframes();
+
+ if (write_phase == 0) {
+ _last_delay_time = delay_time;
+ _delay_samples = delay_samples = CALC_DELAY(delay_time);
+ }
+
+ if (delay_time == _last_delay_time) {
+ const long idelay_samples = (long)delay_samples;
+ const float frac = delay_samples - idelay_samples;
+
+ for (uint32_t i = 0; i < sample_count; i++) {
+ long read_phase = write_phase - (long)delay_samples;
+ const float read = cube_interp(frac,
+ buffer_at(read_phase - 1),
+ buffer_at(read_phase),
+ buffer_at(read_phase + 1),
+ buffer_at(read_phase + 2));
+ buffer_at(write_phase++) = in[i];
+ out[i] = read;
+ }
+ } else {
+ const float next_delay_samples = CALC_DELAY(delay_time);
+ const float delay_samples_slope = (next_delay_samples - delay_samples) / sample_count;
+
+ for (uint32_t i = 0; i < sample_count; i++) {
+ delay_samples += delay_samples_slope;
+ write_phase++;
+ const long read_phase = write_phase - (long)delay_samples;
+ const long idelay_samples = (long)delay_samples;
+ const float frac = delay_samples - idelay_samples;
+ const float read = cube_interp(frac,
+ buffer_at(read_phase - 1),
+ buffer_at(read_phase),
+ buffer_at(read_phase + 1),
+ buffer_at(read_phase + 2));
+ buffer_at(write_phase) = in[i];
+ out[i] = read;
+ }
+
+ _last_delay_time = delay_time;
+ _delay_samples = delay_samples;
+ }
+
+ _write_phase = write_phase;
+
+ NodeBase::post_process(context);
+}
+
+
+} // namespace Internals
+} // namespace Ingen
+
diff --git a/src/engine/internals/Delay.hpp b/src/engine/internals/Delay.hpp
new file mode 100644
index 00000000..077c65f9
--- /dev/null
+++ b/src/engine/internals/Delay.hpp
@@ -0,0 +1,79 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007-2009 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef INGEN_INTERNALS_DELAY_HPP
+#define INGEN_INTERNALS_DELAY_HPP
+
+#include <string>
+#include <math.h>
+#include "types.hpp"
+//#include "Buffer.hpp"
+//#include "BufferFactory.hpp"
+#include "NodeBase.hpp"
+
+namespace Ingen {
+
+class InputPort;
+class OutputPort;
+class InternalPlugin;
+class BufferFactory;
+
+namespace Internals {
+
+
+/** MIDI note input node.
+ *
+ * For pitched instruments like keyboard, etc.
+ *
+ * \ingroup engine
+ */
+class DelayNode : public NodeBase
+{
+public:
+ DelayNode(BufferFactory& bufs, const std::string& path, bool polyphonic, PatchImpl* parent, SampleRate srate);
+ ~DelayNode();
+
+ void activate(BufferFactory& bufs);
+
+ void process(ProcessContext& context);
+
+ static InternalPlugin& internal_plugin();
+
+ float delay_samples() const { return _delay_samples; }
+
+private:
+ inline float& buffer_at(long phase) const { return _buffer[phase & _buffer_mask]; }
+
+ InputPort* _delay_port;
+ InputPort* _in_port;
+ OutputPort* _out_port;
+
+ typedef long Phase;
+
+ float* _buffer;
+ uint32_t _buffer_length;
+ uint32_t _buffer_mask;
+ Phase _write_phase;
+ float _last_delay_time;
+ float _delay_samples;
+};
+
+
+} // namespace Ingen
+} // namespace Internals
+
+#endif // INGEN_INTERNALS_DELAY_HPP
diff --git a/src/engine/internals/Note.cpp b/src/engine/internals/Note.cpp
index 2798a948..fd2dee71 100644
--- a/src/engine/internals/Note.cpp
+++ b/src/engine/internals/Note.cpp
@@ -148,6 +148,11 @@ NoteNode::process(ProcessContext& context)
debug << endl;
#endif
+ if (frames < context.offset())
+ continue;
+ if (frames > context.nframes())
+ break;
+
const FrameTime time = context.start() + (FrameTime)frames;
if (size >= 3) {
diff --git a/src/engine/wscript b/src/engine/wscript
index 12e61121..b551a5bc 100644
--- a/src/engine/wscript
+++ b/src/engine/wscript
@@ -58,6 +58,7 @@ def build(bld):
events/UnregisterClient.cpp
ingen_engine.cpp
internals/Controller.cpp
+ internals/Delay.cpp
internals/Note.cpp
internals/Trigger.cpp
'''