summaryrefslogtreecommitdiffstats
path: root/src/engine/internals
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2010-02-24 23:12:34 +0000
committerDavid Robillard <d@drobilla.net>2010-02-24 23:12:34 +0000
commite853d3dfcf450f6160e19f20b6b67e251c906169 (patch)
tree6b62d2d1a7f3a047f141e58caee4e5e71ac1f4de /src/engine/internals
parent784dc03a78dc338b45111ebdca45371dfaaa6fa9 (diff)
downloadingen-e853d3dfcf450f6160e19f20b6b67e251c906169.tar.gz
ingen-e853d3dfcf450f6160e19f20b6b67e251c906169.tar.bz2
ingen-e853d3dfcf450f6160e19f20b6b67e251c906169.zip
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
Diffstat (limited to 'src/engine/internals')
-rw-r--r--src/engine/internals/Delay.cpp208
-rw-r--r--src/engine/internals/Delay.hpp79
-rw-r--r--src/engine/internals/Note.cpp5
3 files changed, 292 insertions, 0 deletions
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) {