From e853d3dfcf450f6160e19f20b6b67e251c906169 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 24 Feb 2010 23:12:34 +0000 Subject: Add new Delay internal. Preliminary work towards split cycles. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2485 a436a847-0d15-0410-975c-d299462d15a1 --- src/engine/AudioBuffer.cpp | 15 ++- src/engine/Buffer.hpp | 4 +- src/engine/Context.hpp | 24 +++-- src/engine/ControlBindings.cpp | 1 - src/engine/EventBuffer.cpp | 3 +- src/engine/EventBuffer.hpp | 4 +- src/engine/InputPort.cpp | 5 - src/engine/InternalPlugin.cpp | 11 +- src/engine/JackDriver.cpp | 23 ++++- src/engine/LADSPANode.cpp | 7 +- src/engine/LADSPANode.hpp | 3 +- src/engine/LV2Node.cpp | 7 +- src/engine/LV2Node.hpp | 3 +- src/engine/NodeBase.cpp | 11 +- src/engine/NodeBase.hpp | 3 +- src/engine/NodeFactory.cpp | 12 ++- src/engine/NodeImpl.hpp | 4 +- src/engine/ObjectBuffer.cpp | 18 +++- src/engine/ObjectBuffer.hpp | 4 +- src/engine/PatchImpl.cpp | 4 +- src/engine/PatchImpl.hpp | 2 +- src/engine/PluginImpl.cpp | 3 - src/engine/PortImpl.cpp | 4 +- src/engine/PortImpl.hpp | 2 +- src/engine/ProcessContext.hpp | 13 +-- src/engine/ProcessSlave.hpp | 2 +- src/engine/events/SetMetadata.cpp | 4 +- src/engine/internals/Delay.cpp | 208 ++++++++++++++++++++++++++++++++++++++ src/engine/internals/Delay.hpp | 79 +++++++++++++++ src/engine/internals/Note.cpp | 5 + src/engine/wscript | 1 + 31 files changed, 414 insertions(+), 75 deletions(-) create mode 100644 src/engine/internals/Delay.cpp create mode 100644 src/engine/internals/Delay.hpp (limited to 'src/engine') 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 #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 #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(_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::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 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 buf); + void set_port_buffer(uint32_t voice, uint32_t port_num, + IntrusivePtr 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 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 buf); + void set_port_buffer(uint32_t voice, uint32_t port_num, + IntrusivePtr 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 buf); + virtual void set_port_buffer(uint32_t voice, uint32_t port_num, + IntrusivePtr 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(), ¬e_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 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 buf) = 0; + virtual void set_port_buffer(uint32_t voice, uint32_t port_num, + IntrusivePtr 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(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(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 + * + * 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 +#include +#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(¬e_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(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 + * + * 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 +#include +#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 ''' -- cgit v1.2.1