summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2009-11-14 20:44:40 +0000
committerDavid Robillard <d@drobilla.net>2009-11-14 20:44:40 +0000
commit6ae2018e81e7e81e4906e62dc6224ad34298d9c2 (patch)
tree11286438977c4f975b5148dc93b5f4dfafabdbdc
parentcfec427867f42d7aa7bea6dfbb0736b5ce99e9e2 (diff)
downloadingen-6ae2018e81e7e81e4906e62dc6224ad34298d9c2.tar.gz
ingen-6ae2018e81e7e81e4906e62dc6224ad34298d9c2.tar.bz2
ingen-6ae2018e81e7e81e4906e62dc6224ad34298d9c2.zip
Object extension.
Port resize extension. Sensible extension(s) implementation design for Ingen. Replace string port extension support in Ingen with Object port extension. Implement port resize extension in Ingen. Some test plugins for this stuff. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@2260 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--src/client/PluginUI.cpp30
-rw-r--r--src/client/PluginUI.hpp3
l---------src/common/contexts.lv21
-rw-r--r--src/common/interface/DataType.hpp20
l---------src/common/object.lv21
l---------src/common/resize-port.lv21
-rw-r--r--src/engine/AudioBuffer.cpp16
-rw-r--r--src/engine/AudioBuffer.hpp5
-rw-r--r--src/engine/Buffer.cpp8
-rw-r--r--src/engine/Buffer.hpp7
-rw-r--r--src/engine/ConnectionImpl.cpp29
-rw-r--r--src/engine/ConnectionImpl.hpp2
-rw-r--r--src/engine/Context.hpp25
-rw-r--r--src/engine/DuplexPort.cpp6
-rw-r--r--src/engine/DuplexPort.hpp4
-rw-r--r--src/engine/Engine.cpp2
-rw-r--r--src/engine/EventBuffer.cpp23
-rw-r--r--src/engine/EventBuffer.hpp19
-rw-r--r--src/engine/GraphObjectImpl.hpp1
-rw-r--r--src/engine/InputPort.cpp17
-rw-r--r--src/engine/InputPort.hpp4
-rw-r--r--src/engine/JackMidiDriver.cpp8
-rw-r--r--src/engine/LV2BlobFeature.hpp64
-rw-r--r--src/engine/LV2EventFeature.hpp51
-rw-r--r--src/engine/LV2Info.cpp36
-rw-r--r--src/engine/LV2Info.hpp12
-rw-r--r--src/engine/LV2Node.cpp39
-rw-r--r--src/engine/LV2Node.hpp5
-rw-r--r--src/engine/LV2ResizeFeature.hpp68
-rw-r--r--src/engine/MessageContext.cpp33
-rw-r--r--src/engine/MessageContext.hpp2
-rw-r--r--src/engine/MidiDriver.hpp2
-rw-r--r--src/engine/NodeBase.cpp51
-rw-r--r--src/engine/NodeBase.hpp19
-rw-r--r--src/engine/NodeImpl.hpp12
-rw-r--r--src/engine/OSCDriver.hpp2
-rw-r--r--src/engine/ObjectBuffer.cpp119
-rw-r--r--src/engine/ObjectBuffer.hpp (renamed from src/engine/StringBuffer.hpp)32
-rw-r--r--src/engine/OutputPort.cpp8
-rw-r--r--src/engine/OutputPort.hpp4
-rw-r--r--src/engine/PatchImpl.hpp1
-rw-r--r--src/engine/PortImpl.cpp14
-rw-r--r--src/engine/PortImpl.hpp8
-rw-r--r--src/engine/ProcessContext.hpp18
-rw-r--r--src/engine/QueuedEngineInterface.cpp4
-rw-r--r--src/engine/StringBuffer.cpp121
-rw-r--r--src/engine/events/ClearPatch.cpp2
-rw-r--r--src/engine/events/Delete.cpp2
-rw-r--r--src/engine/events/Move.cpp2
-rw-r--r--src/engine/events/RequestMetadata.cpp19
-rw-r--r--src/engine/events/SetPortValue.cpp49
-rw-r--r--src/engine/events/SetPortValue.hpp2
-rw-r--r--src/engine/internals/Controller.cpp3
-rw-r--r--src/engine/internals/Note.cpp4
-rw-r--r--src/engine/internals/Trigger.cpp3
-rw-r--r--src/engine/wscript2
-rw-r--r--src/gui/Configuration.cpp8
-rw-r--r--src/gui/Configuration.hpp2
-rw-r--r--src/gui/ControlPanel.cpp2
-rw-r--r--src/gui/Controls.cpp28
-rw-r--r--src/gui/PatchCanvas.cpp2
-rw-r--r--src/gui/Port.cpp2
-rw-r--r--src/gui/PortMenu.cpp2
-rw-r--r--src/shared/LV2Features.cpp35
-rw-r--r--src/shared/LV2Features.hpp46
-rw-r--r--src/shared/LV2Object.cpp96
-rw-r--r--src/shared/LV2Object.hpp39
-rw-r--r--src/shared/LV2URIMap.cpp12
-rw-r--r--src/shared/LV2URIMap.hpp20
-rw-r--r--src/shared/ResourceImpl.cpp6
-rw-r--r--src/shared/wscript3
71 files changed, 896 insertions, 452 deletions
diff --git a/src/client/PluginUI.cpp b/src/client/PluginUI.cpp
index 3007e723..bb10b3a6 100644
--- a/src/client/PluginUI.cpp
+++ b/src/client/PluginUI.cpp
@@ -17,9 +17,10 @@
#include <iostream>
#include "event.lv2/event-helpers.h"
-#include "string-port.lv2/string-port.h"
+#include "object.lv2/object.h"
#include "shared/LV2Features.hpp"
#include "shared/LV2URIMap.hpp"
+#include "shared/LV2Object.hpp"
#include "PluginUI.hpp"
#include "NodeModel.hpp"
#include "PortModel.hpp"
@@ -56,9 +57,8 @@ lv2_ui_write(LV2UI_Controller controller,
SharedPtr<PortModel> port = ui->node()->ports()[port_index];
- const LV2Features::Feature* f = ui->world()->lv2_features->feature(LV2_URI_MAP_URI);
- LV2URIMap* map = (LV2URIMap*)f->controller;
- assert(map);
+ SharedPtr<Shared::LV2URIMap> map = PtrCast<Shared::LV2URIMap>(
+ ui->world()->lv2_features->feature(LV2_URI_MAP_URI));
// float (special case, always 0)
if (format == 0) {
@@ -68,16 +68,14 @@ lv2_ui_write(LV2UI_Controller controller,
ui->world()->engine->set_port_value(port->path(), Atom(*(float*)buffer));
- // FIXME: this is slow, cache ID
- } else if (format == map->uri_to_id(NULL, "http://lv2plug.in/ns/extensions/ui#Events")) {
- uint32_t midi_event_type = map->uri_to_id(NULL, "http://lv2plug.in/ns/ext/midi#MidiEvent");
- LV2_Event_Buffer* buf = (LV2_Event_Buffer*)buffer;
+ } else if (format == map->ui_format_events) {
+ LV2_Event_Buffer* buf = (LV2_Event_Buffer*)buffer;
LV2_Event_Iterator iter;
- uint8_t* data;
+ uint8_t* data;
lv2_event_begin(&iter, buf);
while (lv2_event_is_valid(&iter)) {
LV2_Event* const ev = lv2_event_get(&iter, &data);
- if (ev->type == midi_event_type) {
+ if (ev->type == map->midi_event) {
// FIXME: bundle multiple events by writing an entire buffer here
ui->world()->engine->set_port_value(port->path(),
Atom("lv2midi:MidiEvent", ev->size, data));
@@ -89,10 +87,11 @@ lv2_ui_write(LV2UI_Controller controller,
lv2_event_increment(&iter);
}
- // FIXME: this is slow, cache ID
- } else if (format == map->uri_to_id(NULL, "http://lv2plug.in/ns/dev/string-port#StringTransfer")) {
- LV2_String_Data* buf = (LV2_String_Data*)buffer;
- ui->world()->engine->set_port_value(port->path(), buf->data);
+ } else if (format == map->object_transfer) {
+ LV2_Object* buf = (LV2_Object*)buffer;
+ Raul::Atom val;
+ Shared::LV2Object::to_atom(ui->world(), buf, val);
+ ui->world()->engine->set_port_value(port->path(), val);
} else {
cerr << "WARNING: Unknown value format " << format
@@ -145,8 +144,9 @@ PluginUI::create(Ingen::Shared::World* world,
if (ui) {
cout << "Found GTK Plugin UI: " << slv2_ui_get_uri(ui) << endl;
ret = SharedPtr<PluginUI>(new PluginUI(world, node));
+ ret->_features = world->lv2_features->lv2_features(node.get());
SLV2UIInstance inst = slv2_ui_instantiate(
- plugin, ui, lv2_ui_write, ret.get(), world->lv2_features->lv2_features());
+ plugin, ui, lv2_ui_write, ret.get(), ret->_features->array());
if (inst) {
ret->set_instance(inst);
diff --git a/src/client/PluginUI.hpp b/src/client/PluginUI.hpp
index d74d0b72..15071433 100644
--- a/src/client/PluginUI.hpp
+++ b/src/client/PluginUI.hpp
@@ -21,6 +21,7 @@
#include "slv2/slv2.h"
#include "raul/SharedPtr.hpp"
#include "module/World.hpp"
+#include "LV2Features.hpp"
namespace Ingen {
namespace Shared { class EngineInterface; }
@@ -54,6 +55,8 @@ private:
Ingen::Shared::World* _world;
SharedPtr<NodeModel> _node;
SLV2UIInstance _instance;
+
+ SharedPtr<Shared::LV2Features::FeatureArray> _features;
};
diff --git a/src/common/contexts.lv2 b/src/common/contexts.lv2
new file mode 120000
index 00000000..acc4d68c
--- /dev/null
+++ b/src/common/contexts.lv2
@@ -0,0 +1 @@
+../../../lv2/dev/contexts.lv2 \ No newline at end of file
diff --git a/src/common/interface/DataType.hpp b/src/common/interface/DataType.hpp
index 4590a9a1..15cdc591 100644
--- a/src/common/interface/DataType.hpp
+++ b/src/common/interface/DataType.hpp
@@ -39,10 +39,11 @@ public:
UNKNOWN = 0,
AUDIO = 1,
CONTROL = 2,
- EVENT = 3,
+ EVENTS = 3,
//MIDI = 4,
//OSC = 5,
- STRING = 6
+ //STRING = 6,
+ OBJECT = 7
};
DataType(const Raul::URI& uri)
@@ -52,10 +53,10 @@ public:
_symbol = AUDIO;
} else if (uri.str() == type_uri(CONTROL)) {
_symbol = CONTROL;
- } else if (uri.str() == type_uri(EVENT)) {
- _symbol = EVENT;
- } else if (uri.str() == type_uri(STRING)) {
- _symbol = STRING;
+ } else if (uri.str() == type_uri(EVENTS)) {
+ _symbol = EVENTS;
+ } else if (uri.str() == type_uri(OBJECT)) {
+ _symbol = OBJECT;
}
}
@@ -73,8 +74,8 @@ public:
inline bool is_audio() { return _symbol == AUDIO; }
inline bool is_control() { return _symbol == CONTROL; }
- inline bool is_event() { return _symbol == EVENT; }
- inline bool is_string() { return _symbol == STRING; }
+ inline bool is_events() { return _symbol == EVENTS; }
+ inline bool is_object() { return _symbol == OBJECT; }
private:
@@ -85,7 +86,8 @@ private:
case 3: return "lv2ev:EventPort";
case 4: return "lv2ev:EventPort"; // MIDI (no longer used)
case 5: return "lv2ev:EventPort"; // OSC (no longer used)
- case 6: return "sp:StringPort";
+ case 6: return "sp:StringPort"; // String Port (no longer used)
+ case 7: return "obj:ObjectPort";
default: return "";
}
}
diff --git a/src/common/object.lv2 b/src/common/object.lv2
new file mode 120000
index 00000000..08017748
--- /dev/null
+++ b/src/common/object.lv2
@@ -0,0 +1 @@
+../../../lv2/dev/object.lv2 \ No newline at end of file
diff --git a/src/common/resize-port.lv2 b/src/common/resize-port.lv2
new file mode 120000
index 00000000..89bdbf96
--- /dev/null
+++ b/src/common/resize-port.lv2
@@ -0,0 +1 @@
+../../../lv2/dev/resize-port.lv2 \ No newline at end of file
diff --git a/src/engine/AudioBuffer.cpp b/src/engine/AudioBuffer.cpp
index 02ebea57..53924ae4 100644
--- a/src/engine/AudioBuffer.cpp
+++ b/src/engine/AudioBuffer.cpp
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include "ingen-config.h"
#include "AudioBuffer.hpp"
+#include "ProcessContext.hpp"
using namespace std;
@@ -211,6 +212,13 @@ AudioBuffer::copy(const Buffer* src, size_t start_sample, size_t end_sample)
}
+void
+AudioBuffer::copy(Context& context, const Buffer* src)
+{
+ copy(src, context.start(), std::min(size(), src->size()));
+}
+
+
/** Accumulate a block of @a src into buffer.
*
* @a start_sample and @a end_sample define the inclusive range to be accumulated.
@@ -268,15 +276,11 @@ AudioBuffer::unjoin()
void
-AudioBuffer::prepare_read(FrameTime start, SampleCount nframes)
+AudioBuffer::prepare_read(Context& context)
{
- // FIXME: nframes parameter doesn't actually work,
- // writing starts from 0 every time
- assert(_size == 1 || nframes == _size);
-
switch (_state) {
case HALF_SET_CYCLE_1:
- if (start > _set_time)
+ if (context.start() > _set_time)
_state = HALF_SET_CYCLE_2;
break;
case HALF_SET_CYCLE_2:
diff --git a/src/engine/AudioBuffer.hpp b/src/engine/AudioBuffer.hpp
index aff990ec..d072ddb3 100644
--- a/src/engine/AudioBuffer.hpp
+++ b/src/engine/AudioBuffer.hpp
@@ -37,6 +37,7 @@ public:
void set_block(Sample val, size_t start_offset, size_t end_offset);
void scale(Sample val, size_t start_sample, size_t end_sample);
void copy(const Buffer* src, size_t start_sample, size_t end_sample);
+ void copy(Context& context, const Buffer* src);
void accumulate(const AudioBuffer* src, size_t start_sample, size_t end_sample);
bool join(Buffer* buf);
@@ -53,8 +54,8 @@ public:
inline Sample& value_at(size_t offset) const
{ assert(offset < _size); return data()[offset]; }
- void prepare_read(FrameTime start, SampleCount nframes);
- void prepare_write(FrameTime start, SampleCount nframes) {}
+ void prepare_read(Context& context);
+ void prepare_write(Context& context) {}
void resize(size_t size);
diff --git a/src/engine/Buffer.cpp b/src/engine/Buffer.cpp
index 14d97314..65e46736 100644
--- a/src/engine/Buffer.cpp
+++ b/src/engine/Buffer.cpp
@@ -17,7 +17,7 @@
#include "AudioBuffer.hpp"
#include "EventBuffer.hpp"
-#include "StringBuffer.hpp"
+#include "ObjectBuffer.hpp"
namespace Ingen {
@@ -30,10 +30,10 @@ Buffer::create(DataType type, size_t size)
return new AudioBuffer(1);
else if (type.is_audio())
return new AudioBuffer(size);
- else if (type.is_event())
+ else if (type.is_events())
return new EventBuffer(size);
- else if (type.is_string())
- return new StringBuffer(size);
+ else if (type.is_object())
+ return new ObjectBuffer(size);
else
throw;
}
diff --git a/src/engine/Buffer.hpp b/src/engine/Buffer.hpp
index a1a56725..adde37f2 100644
--- a/src/engine/Buffer.hpp
+++ b/src/engine/Buffer.hpp
@@ -27,6 +27,7 @@
namespace Ingen {
+class Context;
class Buffer : public boost::noncopyable, public Raul::Deletable
{
@@ -52,10 +53,10 @@ public:
/** Rewind (ie reset read pointer), but leave contents unchanged */
virtual void rewind() const {}
- virtual void copy(const Buffer* src, size_t start_sample, size_t end_sample) = 0;
+ virtual void copy(Context& context, const Buffer* src) = 0;
- virtual void prepare_read(FrameTime start, SampleCount nframes) = 0;
- virtual void prepare_write(FrameTime start, SampleCount nframes) = 0;
+ virtual void prepare_read(Context& context) {}
+ virtual void prepare_write(Context& context) {}
bool is_joined() const { return (_joined_buf != NULL); }
Buffer* joined_buffer() const { return _joined_buf; }
diff --git a/src/engine/ConnectionImpl.cpp b/src/engine/ConnectionImpl.cpp
index 66592bfe..f33c612b 100644
--- a/src/engine/ConnectionImpl.cpp
+++ b/src/engine/ConnectionImpl.cpp
@@ -76,8 +76,11 @@ ConnectionImpl::set_mode()
else if (must_extend())
_mode = EXTEND;
- if (_mode == MIX && type() == DataType::EVENT)
+ if (_mode == MIX && type() == DataType::EVENTS)
_mode = COPY;
+
+ if (type() == DataType::OBJECT)
+ _mode = DIRECT;
}
@@ -123,10 +126,6 @@ ConnectionImpl::prepare_poly(uint32_t poly)
{
_src_port->prepare_poly(poly);
- /*cerr << "CONNECTION PREPARE: " << src_port()->path() << " * " << src_port()->poly()
- << " -> " << dst_port()->path() << " * " << dst_port()->poly()
- << "\t\tmust mix: " << must_mix() << " at poly " << poly << endl;*/
-
if (need_buffer() && !_local_buffer)
_local_buffer = Buffer::create(_dst_port->type(), _dst_port->buffer(0)->size());
}
@@ -152,11 +151,8 @@ ConnectionImpl::apply_poly(Raul::Maid& maid, uint32_t poly)
void
-ConnectionImpl::process(ProcessContext& context)
+ConnectionImpl::process(Context& context)
{
- // FIXME: nframes parameter not used
- assert(_buffer_size == 1 || _buffer_size == context.nframes());
-
/* Thought: A poly output port can be connected to multiple mono input
* ports, which means this mix down would have to happen many times.
* Adding a method to OutputPort that mixes down all it's outputs into
@@ -164,15 +160,15 @@ ConnectionImpl::process(ProcessContext& context)
* would avoid having to mix multiple times. Probably not a very common
* case, but it would be faster anyway. */
- /*std::cerr << src_port()->path() << " * " << src_port()->poly()
+ std::cerr << src_port()->path() << " * " << src_port()->poly()
<< " -> " << dst_port()->path() << " * " << dst_port()->poly()
- << "\t\tmode: " << (int)_mode << std::endl;*/
+ << "\t\tmode: " << (int)_mode << std::endl;
if (_mode == COPY) {
assert(src_port()->poly() == dst_port()->poly());
- const size_t copy_size = std::min(src_port()->buffer_size(), dst_port()->buffer_size());
- for (uint32_t i=0; i < src_port()->poly(); ++i)
- dst_port()->buffer(i)->copy(src_port()->buffer(i), 0, copy_size-1);
+ for (uint32_t i = 0; i < src_port()->poly(); ++i)
+ dst_port()->buffer(i)->copy(context, src_port()->buffer(i));
+
} else if (_mode == MIX) {
assert(type() == DataType::AUDIO || type() == DataType::CONTROL);
@@ -184,7 +180,7 @@ ConnectionImpl::process(ProcessContext& context)
const size_t copy_size = std::min(src_buffer->size(), mix_buf->size());
// Copy src buffer to start of mix buffer
- mix_buf->copy((AudioBuffer*)src_port()->buffer(0), 0, copy_size-1);
+ mix_buf->copy(context, src_buffer);
// Write last value of src buffer to remainder of dst buffer, if necessary
if (copy_size < mix_buf->size())
@@ -229,9 +225,10 @@ ConnectionImpl::process(ProcessContext& context)
if (copy_size < dst_buf->size())
dst_buf->set_block(src_buf->value_at(copy_size - 1), copy_size, dst_buf->size() - 1);
}
+
} else if (_mode == DIRECT) {
for (uint32_t j=0; j < src_port()->poly(); ++j)
- src_port()->buffer(j)->prepare_read(context.start(), context.nframes());
+ src_port()->buffer(j)->prepare_read(context);
}
}
diff --git a/src/engine/ConnectionImpl.hpp b/src/engine/ConnectionImpl.hpp
index dd8c6a2c..a4ad281b 100644
--- a/src/engine/ConnectionImpl.hpp
+++ b/src/engine/ConnectionImpl.hpp
@@ -57,7 +57,7 @@ public:
bool pending_disconnection() { return _pending_disconnection; }
void pending_disconnection(bool b) { _pending_disconnection = b; }
- void process(ProcessContext& context);
+ void process(Context& context);
/** Get the buffer for a particular voice.
* A Connection is smart - it knows the destination port requesting the
diff --git a/src/engine/Context.hpp b/src/engine/Context.hpp
index db19d5f9..8d3085b8 100644
--- a/src/engine/Context.hpp
+++ b/src/engine/Context.hpp
@@ -18,6 +18,8 @@
#ifndef CONTEXT_H
#define CONTEXT_H
+#include "EventSink.hpp"
+
namespace Ingen {
class Engine;
@@ -33,15 +35,32 @@ public:
Context(Engine& engine, ID id)
: _id(id)
, _engine(engine)
+ , _event_sink(engine, 1024) // FIXME: size?
+ , _start(0)
+ , _realtime(true)
{}
virtual ~Context() {}
- inline Engine& engine() const { return _engine; }
+ ID id() const { return _id; }
+
+ void locate(FrameTime s) { _start = s; }
+
+ inline Engine& engine() const { return _engine; }
+ inline FrameTime start() const { return _start; }
+ inline bool realtime() const { return _realtime; }
+
+ inline const EventSink& event_sink() const { return _event_sink; }
+ inline EventSink& event_sink() { return _event_sink; }
protected:
- ID _id; ///< Fast ID for this context
- Engine& _engine; ///< Engine we're running in
+ 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
};
diff --git a/src/engine/DuplexPort.cpp b/src/engine/DuplexPort.cpp
index 2c4e81b9..78a2bb94 100644
--- a/src/engine/DuplexPort.cpp
+++ b/src/engine/DuplexPort.cpp
@@ -54,7 +54,7 @@ DuplexPort::DuplexPort(
/** Prepare for the execution of parent patch */
void
-DuplexPort::pre_process(ProcessContext& context)
+DuplexPort::pre_process(Context& context)
{
/*cerr << endl << "{ duplex pre" << endl;
cerr << path() << " duplex pre: fixed buffers: " << fixed_buffers() << endl;
@@ -65,7 +65,7 @@ DuplexPort::pre_process(ProcessContext& context)
if (_is_output) {
for (uint32_t i=0; i < _poly; ++i)
if (!_buffers->at(i)->is_joined())
- _buffers->at(i)->prepare_write(context.start(), context.nframes());
+ _buffers->at(i)->prepare_write(context);
// Otherwise, we're a patch input, do whatever a normal node's input port does
// (mix down inputs from an outside "patch is a node" perspective)
@@ -85,7 +85,7 @@ DuplexPort::pre_process(ProcessContext& context)
/** Finalize after the execution of parent patch (deliver outputs) */
void
-DuplexPort::post_process(ProcessContext& context)
+DuplexPort::post_process(Context& context)
{
/*cerr << endl << "{ duplex post" << endl;
cerr << path() << " duplex post: fixed buffers: " << fixed_buffers() << endl;
diff --git a/src/engine/DuplexPort.hpp b/src/engine/DuplexPort.hpp
index 97816acb..882bab73 100644
--- a/src/engine/DuplexPort.hpp
+++ b/src/engine/DuplexPort.hpp
@@ -50,8 +50,8 @@ public:
virtual ~DuplexPort() {}
- void pre_process(ProcessContext& context);
- void post_process(ProcessContext& context);
+ void pre_process(Context& context);
+ void post_process(Context& context);
bool is_input() const { return !_is_output; }
bool is_output() const { return _is_output; }
diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp
index 8f119248..619ead5e 100644
--- a/src/engine/Engine.cpp
+++ b/src/engine/Engine.cpp
@@ -105,7 +105,7 @@ Engine::driver(DataType type, EventType event_type)
{
if (type == DataType::AUDIO) {
return _audio_driver.get();
- } else if (type == DataType::EVENT) {
+ } else if (type == DataType::EVENTS) {
if (event_type == EventType::MIDI) {
return _midi_driver;
} else if (event_type == EventType::OSC) {
diff --git a/src/engine/EventBuffer.cpp b/src/engine/EventBuffer.cpp
index f8b97595..d92ecae1 100644
--- a/src/engine/EventBuffer.cpp
+++ b/src/engine/EventBuffer.cpp
@@ -18,10 +18,11 @@
#define __STDC_LIMIT_MACROS 1
#include <stdint.h>
#include <iostream>
-#include "ingen-config.h"
-#include "EventBuffer.hpp"
#include "event.lv2/event.h"
#include "event.lv2/event-helpers.h"
+#include "ingen-config.h"
+#include "EventBuffer.hpp"
+#include "ProcessContext.hpp"
using namespace std;
@@ -33,11 +34,11 @@ using namespace Shared;
* \a capacity is in bytes (not number of events).
*/
EventBuffer::EventBuffer(size_t capacity)
- : Buffer(DataType(DataType::EVENT), capacity)
+ : Buffer(DataType(DataType::EVENTS), capacity)
, _local_buf(new LV2EventBuffer(capacity))
{
_buf = _local_buf;
- reset(0);
+ clear();
//cerr << "Creating MIDI Buffer " << _buf << ", capacity = " << _buf->capacity << endl;
}
@@ -71,22 +72,21 @@ EventBuffer::unjoin()
void
-EventBuffer::prepare_read(FrameTime start, SampleCount nframes)
+EventBuffer::prepare_read(Context& context)
{
rewind();
- _this_nframes = nframes;
}
void
-EventBuffer::prepare_write(FrameTime start, SampleCount nframes)
+EventBuffer::prepare_write(Context& context)
{
- reset(nframes);
+ clear();
}
-/** FIXME: parameters ignored */
+
void
-EventBuffer::copy(const Buffer* src_buf, size_t start_sample, size_t end_sample)
+EventBuffer::copy(Context& context, const Buffer* src_buf)
{
const EventBuffer* src = dynamic_cast<const EventBuffer*>(src_buf);
assert(src);
@@ -97,7 +97,6 @@ EventBuffer::copy(const Buffer* src_buf, size_t start_sample, size_t end_sample)
src->rewind();
_buf->copy(*src->_buf);
- _this_nframes = end_sample - start_sample;
assert(event_count() == src->event_count());
}
@@ -114,7 +113,7 @@ EventBuffer::merge(const EventBuffer& a, const EventBuffer& b)
// Die if a merge isn't necessary as it's expensive
assert(a.size() > 0 && b.size() > 0);
- reset(_this_nframes);
+ clear();
a.rewind();
b.rewind();
diff --git a/src/engine/EventBuffer.hpp b/src/engine/EventBuffer.hpp
index f89705b0..cafa71bd 100644
--- a/src/engine/EventBuffer.hpp
+++ b/src/engine/EventBuffer.hpp
@@ -34,17 +34,17 @@ public:
bool join(Buffer* buf);
void unjoin();
- void clear() { reset(_this_nframes); }
+ void clear() { _buf->reset(); }
void* raw_data() { return _buf; }
const void* raw_data() const { return _buf; }
void rewind() const { _buf->rewind(); }
- void prepare_read(FrameTime start, SampleCount nframes);
- void prepare_write(FrameTime start, SampleCount nframes);
+ void prepare_read(Context& context);
+ void prepare_write(Context& context);
- void copy(const Buffer* src, size_t start_sample, size_t end_sample);
+ void copy(Context& context, const Buffer* src);
bool merge(const EventBuffer& a, const EventBuffer& b);
bool increment() const { return _buf->increment(); }
@@ -52,14 +52,8 @@ public:
inline uint32_t latest_frames() const { return _buf->latest_frames(); }
inline uint32_t latest_subframes() const { return _buf->latest_subframes(); }
- inline uint32_t this_nframes() const { return _this_nframes; }
inline uint32_t event_count() const { return _buf->event_count(); }
- inline void reset(SampleCount nframes) {
- _this_nframes = nframes;
- _buf->reset();
- }
-
inline bool get_event(uint32_t* frames,
uint32_t* subframes,
uint16_t* type,
@@ -81,9 +75,8 @@ public:
}
private:
- LV2EventBuffer* _buf; ///< Contents (maybe belong to _joined_buf)
- LV2EventBuffer* _local_buf; ///< Local contents
- uint32_t _this_nframes; ///< Current cycle nframes
+ LV2EventBuffer* _buf; ///< Contents (maybe belong to _joined_buf)
+ LV2EventBuffer* _local_buf; ///< Local contents
};
diff --git a/src/engine/GraphObjectImpl.hpp b/src/engine/GraphObjectImpl.hpp
index c8b0c13c..66bda3e2 100644
--- a/src/engine/GraphObjectImpl.hpp
+++ b/src/engine/GraphObjectImpl.hpp
@@ -32,6 +32,7 @@ namespace Raul { class Maid; }
namespace Ingen {
class PatchImpl;
+class Context;
class ProcessContext;
diff --git a/src/engine/InputPort.cpp b/src/engine/InputPort.cpp
index 31cb3e92..5d3a0627 100644
--- a/src/engine/InputPort.cpp
+++ b/src/engine/InputPort.cpp
@@ -188,7 +188,7 @@ InputPort::remove_connection(const OutputPort* src_port)
/** Prepare buffer for access, mixing if necessary. Realtime safe.
*/
void
-InputPort::pre_process(ProcessContext& context)
+InputPort::pre_process(Context& context)
{
// If value has been set (e.g. events pushed) by the user,
// don't do anything this cycle to avoid smashing the value
@@ -198,7 +198,7 @@ InputPort::pre_process(ProcessContext& context)
// No connections, just prepare buffers for reading by our node
if (_connections.size() == 0) {
for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_read(context.start(), context.nframes());
+ buffer(i)->prepare_read(context);
return;
}
@@ -210,7 +210,7 @@ InputPort::pre_process(ProcessContext& context)
if (can_direct()) {
for (uint32_t i=0; i < _poly; ++i) {
_buffers->at(i)->join(_connections.front()->buffer(i));
- _buffers->at(i)->prepare_read(context.start(), context.nframes());
+ _buffers->at(i)->prepare_read(context);
}
connect_buffers();
return;
@@ -235,8 +235,7 @@ InputPort::pre_process(ProcessContext& context)
if (_type == DataType::CONTROL || _type == DataType::AUDIO) {
for (uint32_t voice=0; voice < _poly; ++voice) {
// Copy first connection
- buffer(voice)->copy(
- _connections.front()->buffer(voice), 0, _buffer_size-1);
+ buffer(voice)->copy(context, _connections.front()->buffer(voice));
// Accumulate the rest
if (_connections.size() > 1) {
@@ -254,11 +253,11 @@ InputPort::pre_process(ProcessContext& context)
cerr << "WARNING: MIDI mixing not implemented, only first connection used." << endl;
// Copy first connection
- buffer(0)->copy(_connections.front()->buffer(0), 0, _buffer_size-1);
+ buffer(0)->copy(context, _connections.front()->buffer(0));
}
for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_read(context.start(), context.nframes());
+ buffer(i)->prepare_read(context);
if (_broadcast)
broadcast_value(context, false);
@@ -266,12 +265,12 @@ InputPort::pre_process(ProcessContext& context)
void
-InputPort::post_process(ProcessContext& context)
+InputPort::post_process(Context& context)
{
// Prepare buffers for next cycle
if (!can_direct())
for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_write(context.start(), context.nframes());
+ buffer(i)->prepare_write(context);
_set_by_user = false;
diff --git a/src/engine/InputPort.hpp b/src/engine/InputPort.hpp
index 4f27835a..81702b34 100644
--- a/src/engine/InputPort.hpp
+++ b/src/engine/InputPort.hpp
@@ -64,8 +64,8 @@ public:
bool prepare_poly(uint32_t poly);
bool apply_poly(Raul::Maid& maid, uint32_t poly);
- void pre_process(ProcessContext& context);
- void post_process(ProcessContext& context);
+ void pre_process(Context& context);
+ void post_process(Context& context);
bool is_connected() const { return (_connections.size() > 0); }
diff --git a/src/engine/JackMidiDriver.cpp b/src/engine/JackMidiDriver.cpp
index 61aacc06..1cb46c3e 100644
--- a/src/engine/JackMidiDriver.cpp
+++ b/src/engine/JackMidiDriver.cpp
@@ -106,7 +106,7 @@ JackMidiPort::pre_process(ProcessContext& context)
void* jack_buffer = jack_port_get_buffer(_jack_port, context.nframes());
const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer);
- patch_buf->prepare_write(context.start(), context.nframes());
+ patch_buf->prepare_write(context);
// Copy events from Jack port buffer into patch port buffer
for (jack_nframes_t i=0; i < event_count; ++i) {
@@ -140,7 +140,7 @@ JackMidiPort::post_process(ProcessContext& context)
assert(_patch_port->poly() == 1);
assert(patch_buf);
- patch_buf->prepare_read(context.start(), context.nframes());
+ patch_buf->prepare_read(context);
jack_midi_clear_buffer(jack_buf);
uint32_t frames = 0;
@@ -173,8 +173,8 @@ JackMidiDriver::JackMidiDriver(Engine& engine)
, _is_activated(false)
, _is_enabled(false)
{
- const Shared::LV2Features::Feature* f = engine.world()->lv2_features->feature(LV2_URI_MAP_URI);
- Shared::LV2URIMap* map = (Shared::LV2URIMap*)f->controller;
+ SharedPtr<Shared::LV2URIMap> map = PtrCast<Shared::LV2URIMap>(
+ _engine.world()->lv2_features->feature(LV2_URI_MAP_URI));
_midi_event_type = map->uri_to_id(NULL, "http://lv2plug.in/ns/ext/midi#MidiEvent");
}
diff --git a/src/engine/LV2BlobFeature.hpp b/src/engine/LV2BlobFeature.hpp
new file mode 100644
index 00000000..c672b7ac
--- /dev/null
+++ b/src/engine/LV2BlobFeature.hpp
@@ -0,0 +1,64 @@
+/* This file is part of Ingen.
+ * Copyright (C) 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 LV2_BLOB_FEATURE_H
+#define LV2_BLOB_FEATURE_H
+
+#include "shared/LV2Features.hpp"
+
+namespace Ingen {
+
+struct BlobFeature : public Shared::LV2Features::Feature {
+ BlobFeature() {
+ LV2_Blob_Support* data = (LV2_Blob_Support*)malloc(sizeof(LV2_Blob_Support));
+ data->data = NULL;
+ data->reference_size = sizeof(LV2_Blob*);
+ data->lv2_blob_new = &blob_new;
+ data->lv2_reference_get = &reference_get;
+ data->lv2_reference_copy = &reference_copy;
+ data->lv2_reference_reset = &reference_reset;
+ _feature.URI = LV2_BLOB_SUPPORT_URI;
+ _feature.data = data;
+ }
+
+ static void blob_new(LV2_Blob_Support_Data data,
+ LV2_Reference* reference,
+ LV2_Blob_Destroy destroy_func,
+ uint32_t type,
+ uint32_t size) {}
+
+ static LV2_Blob* reference_get(LV2_Blob_Support_Data data,
+ LV2_Reference* ref) { return 0; }
+
+ static void reference_copy(LV2_Blob_Support_Data data,
+ LV2_Reference* dst,
+ LV2_Reference* src) {}
+
+ static void reference_reset(LV2_Blob_Support_Data data,
+ LV2_Reference* ref) {}
+
+ SharedPtr<LV2_Feature> feature(Shared::Node*) {
+ return SharedPtr<LV2_Feature>(&_feature, NullDeleter<LV2_Feature>);
+ }
+
+private:
+ LV2_Feature _feature;
+};
+
+} // namespace Ingen
+
+#endif // LV2_BLOB_FEATURE_H
diff --git a/src/engine/LV2EventFeature.hpp b/src/engine/LV2EventFeature.hpp
new file mode 100644
index 00000000..b2baaeec
--- /dev/null
+++ b/src/engine/LV2EventFeature.hpp
@@ -0,0 +1,51 @@
+/* This file is part of Ingen.
+ * Copyright (C) 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 LV2_EVENT_FEATURE_H
+#define LV2_EVENT_FEATURE_H
+
+#include "shared/LV2Features.hpp"
+
+namespace Ingen {
+
+struct EventFeature : public Shared::LV2Features::Feature {
+ EventFeature() {
+ LV2_Event_Feature* data = (LV2_Event_Feature*)malloc(sizeof(LV2_Event_Feature));
+ data->lv2_event_ref = &event_ref;
+ data->lv2_event_unref = &event_unref;
+ data->callback_data = this;
+ _feature.URI = LV2_EVENT_URI;
+ _feature.data = data;
+ }
+
+ static uint32_t event_ref(LV2_Event_Callback_Data callback_data,
+ LV2_Event* event) { return 0; }
+
+ static uint32_t event_unref(LV2_Event_Callback_Data callback_data,
+ LV2_Event* event) { return 0; }
+
+ SharedPtr<LV2_Feature> feature(Shared::Node*) {
+ return SharedPtr<LV2_Feature>(&_feature, NullDeleter<LV2_Feature>);
+ }
+
+private:
+ LV2_Feature _feature;
+};
+
+} // namespace Ingen
+
+#endif // LV2_EVENT_FEATURE_H
diff --git a/src/engine/LV2Info.cpp b/src/engine/LV2Info.cpp
index 10541d0c..e94deaad 100644
--- a/src/engine/LV2Info.cpp
+++ b/src/engine/LV2Info.cpp
@@ -19,8 +19,13 @@
#include <cassert>
#include <iostream>
#include <stdint.h>
+#include "object.lv2/object.h"
#include "LV2Info.hpp"
#include "module/World.hpp"
+#include "LV2Features.hpp"
+#include "LV2EventFeature.hpp"
+#include "LV2BlobFeature.hpp"
+#include "LV2ResizeFeature.hpp"
using namespace std;
@@ -32,24 +37,19 @@ LV2Info::LV2Info(Ingen::Shared::World* world)
, control_class(slv2_value_new_uri(world->slv2_world, SLV2_PORT_CLASS_CONTROL))
, audio_class(slv2_value_new_uri(world->slv2_world, SLV2_PORT_CLASS_AUDIO))
, event_class(slv2_value_new_uri(world->slv2_world, SLV2_PORT_CLASS_EVENT))
- , string_class(slv2_value_new_uri(world->slv2_world,
- "http://lv2plug.in/ns/dev/string-port#StringPort"))
+ , object_port_class(slv2_value_new_uri(world->slv2_world, LV2_OBJECT_URI "#ObjectPort"))
, _world(world)
{
assert(world);
- LV2_Event_Feature* ev_data = (LV2_Event_Feature*)malloc(sizeof(LV2_Event_Feature));
- ev_data->lv2_event_ref = &LV2Info::event_ref;
- ev_data->lv2_event_unref = &LV2Info::event_ref;
- ev_data->callback_data = this;
- LV2_Feature* ev_feature = (LV2_Feature*)malloc(sizeof(LV2_Event_Feature));
- ev_feature->URI = LV2_EVENT_URI;
- ev_feature->data = ev_data;
-
- world->lv2_features->add_feature(LV2_EVENT_URI, ev_feature, ev_data);
+ world->lv2_features->add_feature(LV2_EVENT_URI,
+ SharedPtr<Shared::LV2Features::Feature>(new EventFeature()));
+ world->lv2_features->add_feature(LV2_BLOB_SUPPORT_URI,
+ SharedPtr<Shared::LV2Features::Feature>(new BlobFeature()));
+ world->lv2_features->add_feature(LV2_RESIZE_PORT_URI,
+ SharedPtr<Shared::LV2Features::Feature>(new ResizeFeature()));
}
-
LV2Info::~LV2Info()
{
slv2_value_free(input_class);
@@ -57,17 +57,7 @@ LV2Info::~LV2Info()
slv2_value_free(control_class);
slv2_value_free(audio_class);
slv2_value_free(event_class);
- slv2_value_free(string_class);
-}
-
-
-uint32_t
-LV2Info::event_ref(LV2_Event_Callback_Data callback_data,
- LV2_Event* event)
-{
- return 0;
+ slv2_value_free(object_port_class);
}
-
-
} // namespace Ingen
diff --git a/src/engine/LV2Info.hpp b/src/engine/LV2Info.hpp
index 6f34dc57..8d4478aa 100644
--- a/src/engine/LV2Info.hpp
+++ b/src/engine/LV2Info.hpp
@@ -31,13 +31,16 @@
#include "shared/LV2Features.hpp"
#include "uri-map.lv2/uri-map.h"
#include "event.lv2/event.h"
+#include "object.lv2/object.h"
+#include "resize-port.lv2/resize-port.h"
namespace Ingen {
+namespace Shared { class Node; }
/** Stuff that may need to be passed to an LV2 plugin (i.e. LV2 features).
*/
-class LV2Info : public Shared::LV2URIMap {
+class LV2Info {
public:
LV2Info(Ingen::Shared::World* world);
~LV2Info();
@@ -47,16 +50,11 @@ public:
SLV2Value control_class;
SLV2Value audio_class;
SLV2Value event_class;
- SLV2Value string_class;
+ SLV2Value object_port_class;
Ingen::Shared::World& world() { return *_world; }
SLV2World lv2_world() { return _world->slv2_world; }
- static uint32_t event_ref(LV2_Event_Callback_Data callback_data,
- LV2_Event* event);
-
- LV2_Feature** lv2_features() const { return _world->lv2_features->lv2_features(); }
-
private:
Ingen::Shared::World* _world;
};
diff --git a/src/engine/LV2Node.cpp b/src/engine/LV2Node.cpp
index 70ee2e08..c12171e9 100644
--- a/src/engine/LV2Node.cpp
+++ b/src/engine/LV2Node.cpp
@@ -28,6 +28,7 @@
#include "EventBuffer.hpp"
#include "OutputPort.hpp"
#include "ProcessContext.hpp"
+#include "MessageContext.hpp"
using namespace std;
using namespace Raul;
@@ -81,9 +82,8 @@ LV2Node::prepare_poly(uint32_t poly)
SharedPtr<LV2Info> info = _lv2_plugin->lv2_info();
_prepared_instances = new Raul::Array<SLV2Instance>(poly, *_instances);
for (uint32_t i = _polyphony; i < _prepared_instances->size(); ++i) {
- // FIXME: features array (in NodeFactory) must be passed!
_prepared_instances->at(i) = slv2_plugin_instantiate(
- _lv2_plugin->slv2_plugin(), _srate, info->lv2_features());
+ _lv2_plugin->slv2_plugin(), _srate, _features->array());
if (_prepared_instances->at(i) == NULL) {
cerr << "Failed to instantiate plugin!" << endl;
@@ -151,11 +151,13 @@ LV2Node::instantiate()
_ports = new Raul::Array<PortImpl*>(num_ports, NULL);
_instances = new Raul::Array<SLV2Instance>(_polyphony, NULL);
+ _features = info->world().lv2_features->lv2_features(this);
+
uint32_t port_buffer_size = 0;
SLV2Value ctx_ext_uri = slv2_value_new_uri(info->lv2_world(), LV2_CONTEXT_MESSAGE);
for (uint32_t i=0; i < _polyphony; ++i) {
- (*_instances)[i] = slv2_plugin_instantiate(plug, _srate, info->lv2_features());
+ (*_instances)[i] = slv2_plugin_instantiate(plug, _srate, _features->array());
if ((*_instances)[i] == NULL) {
cerr << "Failed to instantiate plugin!" << endl;
return false;
@@ -213,10 +215,10 @@ LV2Node::instantiate()
data_type = DataType::AUDIO;
port_buffer_size = _buffer_size;
} else if (slv2_port_is_a(plug, id, info->event_class)) {
- data_type = DataType::EVENT;
+ data_type = DataType::EVENTS;
port_buffer_size = _buffer_size;
- } else if (slv2_port_is_a(plug, id, info->string_class)) {
- data_type = DataType::STRING;
+ } else if (slv2_port_is_a(plug, id, info->object_port_class)) {
+ data_type = DataType::OBJECT;
port_buffer_size = 0;
// Get default value, and its length
@@ -275,7 +277,7 @@ LV2Node::instantiate()
for (uint32_t i = 0; i < slv2_values_size(contexts); ++i) {
SLV2Value c = slv2_values_get_at(contexts, i);
const char* context = slv2_value_as_string(c);
- if (!strcmp("http://lv2plug.in/ns/dev/contexts#MessageContext", context)) {
+ if (!strcmp(LV2_CONTEXT_MESSAGE, context)) {
cerr << _lv2_plugin->uri() << " port " << i << " has message context" << endl;
if (!_message_funcs) {
cerr << _lv2_plugin->uri()
@@ -331,13 +333,18 @@ LV2Node::deactivate()
void
-LV2Node::message_process(MessageContext& context, uint32_t* inputs, uint32_t* outputs)
+LV2Node::message_run(MessageContext& context)
{
- // FIXME: voice
- if (_message_funcs)
- (*_message_funcs->message_run)((*_instances)[0]->lv2_handle, inputs, outputs);
+ for (size_t i = 0; i < num_ports(); ++i) {
+ PortImpl* const port = _ports->at(i);
+ if (port->context() == Context::MESSAGE)
+ port->pre_process(context);
+ }
- /* MESSAGE PROCESS */
+ if (!_valid_ports)
+ _valid_ports = calloc(num_ports() / 8, 1);
+ if (_message_funcs)
+ (*_message_funcs->message_run)((*_instances)[0]->lv2_handle, _valid_ports, _valid_ports);
}
@@ -357,15 +364,7 @@ void
LV2Node::set_port_buffer(uint32_t voice, uint32_t port_num, Buffer* buf)
{
assert(voice < _polyphony);
-
slv2_instance_connect_port((*_instances)[voice], port_num, buf->raw_data());
- if ((*_ports).at(port_num)->context() == Context::MESSAGE) {
- assert(_message_funcs);
- assert(_message_funcs->message_connect_port);
- (*_message_funcs->message_connect_port)((*_instances)[voice]->lv2_handle, port_num, buf->raw_data());
- } else {
- slv2_instance_connect_port((*_instances)[voice], port_num, buf->raw_data());
- }
}
diff --git a/src/engine/LV2Node.hpp b/src/engine/LV2Node.hpp
index dd4c80c5..8a543f2d 100644
--- a/src/engine/LV2Node.hpp
+++ b/src/engine/LV2Node.hpp
@@ -23,6 +23,7 @@
#include "lv2_contexts.h"
#include "types.hpp"
#include "NodeBase.hpp"
+#include "LV2Features.hpp"
namespace Ingen {
@@ -53,7 +54,7 @@ public:
void activate();
void deactivate();
- void message_process(MessageContext& context, uint32_t* ins, uint32_t* outs);
+ void message_run(MessageContext& context);
void process(ProcessContext& context);
@@ -65,6 +66,8 @@ protected:
Raul::Array<SLV2Instance>* _prepared_instances;
LV2MessageContext* _message_funcs;
+
+ SharedPtr<Shared::LV2Features::FeatureArray> _features;
};
diff --git a/src/engine/LV2ResizeFeature.hpp b/src/engine/LV2ResizeFeature.hpp
new file mode 100644
index 00000000..90452552
--- /dev/null
+++ b/src/engine/LV2ResizeFeature.hpp
@@ -0,0 +1,68 @@
+/* This file is part of Ingen.
+ * Copyright (C) 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 LV2_RESIZE_FEATURE_H
+#define LV2_RESIZE_FEATURE_H
+
+#include <iostream>
+#include "shared/LV2Features.hpp"
+#include "NodeImpl.hpp"
+#include "PortImpl.hpp"
+
+using namespace std;
+
+namespace Ingen {
+
+struct ResizeFeature : public Shared::LV2Features::Feature {
+ static bool resize_port(LV2_Resize_Port_Feature_Data data,
+ uint32_t index,
+ size_t size) {
+ NodeImpl* node = (NodeImpl*)data;
+ PortImpl* port = node->port_impl(index);
+ if (port->context() == Context::MESSAGE) {
+ cout << "Resizing " << port->path() << " to " << size << " bytes" << endl;
+ port->buffer(0)->resize(size);
+ port->connect_buffers();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static void delete_feature(LV2_Feature* feature) {
+ free(feature->data);
+ free(feature);
+ }
+
+ SharedPtr<LV2_Feature> feature(Shared::Node* n) {
+ NodeImpl* node = dynamic_cast<NodeImpl*>(n);
+ if (!node)
+ return SharedPtr<LV2_Feature>();
+ LV2_Resize_Port_Feature* data
+ = (LV2_Resize_Port_Feature*)malloc(sizeof(LV2_Resize_Port_Feature));
+ data->data = node;
+ data->resize_port = &resize_port;
+ LV2_Feature* f = (LV2_Feature*)malloc(sizeof(LV2_Feature));
+ f->URI = LV2_RESIZE_PORT_URI;
+ f->data = data;
+ return SharedPtr<LV2_Feature>(f, &delete_feature);
+ }
+};
+
+} // namespace Ingen
+
+#endif // LV2_RESIZE_FEATURE_H
diff --git a/src/engine/MessageContext.cpp b/src/engine/MessageContext.cpp
index 355a4361..c0f4d3a6 100644
--- a/src/engine/MessageContext.cpp
+++ b/src/engine/MessageContext.cpp
@@ -15,19 +15,46 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <iostream>
#include "raul/Atom.hpp"
+#include "ConnectionImpl.hpp"
+#include "Engine.hpp"
#include "MessageContext.hpp"
#include "NodeImpl.hpp"
+#include "PatchImpl.hpp"
+#include "PortImpl.hpp"
+#include "ProcessContext.hpp"
+
+using namespace std;
namespace Ingen {
void
MessageContext::run(NodeImpl* node)
{
- uint32_t inputs, outputs;
- node->message_process(*this, &inputs, &outputs);
+ node->message_run(*this);
+
+ void* valid_ports = node->valid_ports();
+ PatchImpl* patch = node->parent_patch();
+
+ cout << "MESSAGE RUN " << node->path() << " {" << endl;
+ for (uint32_t i = 0; i < node->num_ports(); ++i) {
+ PortImpl* p = node->port_impl(i);
+ if (p->is_output() && p->context() == Context::MESSAGE &&
+ lv2_contexts_port_is_valid(valid_ports, i)) {
+ PatchImpl::Connections& wires = patch->connections();
+ for (PatchImpl::Connections::iterator c = wires.begin(); c != wires.end(); ++c) {
+ ConnectionImpl* ci = dynamic_cast<ConnectionImpl*>(c->get());
+ if (ci->src_port() == p) {
+ ci->dst_port()->pre_process(*_engine.message_context());
+ run(ci->dst_port()->parent_node());
+ }
+ }
+ }
+ }
+ cout << "}" << endl;
- // Don't care what the plugin output, yet...
+ node->reset_valid_ports();
}
} // namespace Ingen
diff --git a/src/engine/MessageContext.hpp b/src/engine/MessageContext.hpp
index 6275f1d3..9d17d920 100644
--- a/src/engine/MessageContext.hpp
+++ b/src/engine/MessageContext.hpp
@@ -24,7 +24,7 @@ namespace Ingen {
class NodeImpl;
-/** Context of a message_process() call.
+/** Context of a message_run() call.
*
* The message context is a non-hard-realtime thread used to execute things
* that can take too long to execute in an audio thread, and do sloppy timed
diff --git a/src/engine/MidiDriver.hpp b/src/engine/MidiDriver.hpp
index eb27463a..86b54986 100644
--- a/src/engine/MidiDriver.hpp
+++ b/src/engine/MidiDriver.hpp
@@ -36,7 +36,7 @@ class AudioDriver;
class MidiDriver : public Driver
{
public:
- MidiDriver() : Driver(Shared::DataType::EVENT) {}
+ MidiDriver() : Driver(Shared::DataType::EVENTS) {}
virtual void attach(AudioDriver& master) {}
diff --git a/src/engine/NodeBase.cpp b/src/engine/NodeBase.cpp
index bdacfe80..25660c37 100644
--- a/src/engine/NodeBase.cpp
+++ b/src/engine/NodeBase.cpp
@@ -40,14 +40,15 @@ NodeBase::NodeBase(PluginImpl* plugin, const string& name, bool polyphonic, Patc
, _polyphony((polyphonic && parent) ? parent->internal_polyphony() : 1)
, _srate(srate)
, _buffer_size(buffer_size)
- , _activated(false)
- , _traversed(false)
+ , _valid_ports(NULL)
, _input_ready(1)
, _process_lock(0)
, _n_inputs_ready(0)
, _ports(NULL)
, _providers(new Raul::List<NodeImpl*>())
, _dependants(new Raul::List<NodeImpl*>())
+ , _activated(false)
+ , _traversed(false)
{
assert(_plugin);
assert(_polyphony > 0);
@@ -62,6 +63,8 @@ NodeBase::~NodeBase()
delete _providers;
delete _dependants;
+
+ free(_valid_ports);
}
@@ -202,27 +205,59 @@ NodeBase::signal_input_ready()
/** Prepare to run a cycle (in the audio thread)
*/
void
-NodeBase::pre_process(ProcessContext& context)
+NodeBase::pre_process(Context& context)
{
assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
// Mix down any ports with multiple inputs
- for (size_t i=0; i < num_ports(); ++i)
- _ports->at(i)->pre_process(context);
+ for (size_t i=0; i < num_ports(); ++i) {
+ PortImpl* const port = _ports->at(i);
+ if (port->context() == Context::AUDIO)
+ port->pre_process(context);
+ }
}
/** Prepare to run a cycle (in the audio thread)
*/
void
-NodeBase::post_process(ProcessContext& context)
+NodeBase::post_process(Context& context)
{
assert(ThreadManager::current_thread_id() == THREAD_PROCESS);
/* Write output ports */
- if (_ports)
- for (size_t i=0; i < _ports->size(); ++i)
+ for (size_t i=0; _ports && i < _ports->size(); ++i) {
+ PortImpl* const port = _ports->at(i);
+ if (port->context() == Context::AUDIO)
_ports->at(i)->post_process(context);
+ }
+}
+
+
+/** Flag a port as set (for message context)
+ */
+void
+NodeBase::set_port_valid(uint32_t port_index)
+{
+ // Allocate enough space for one bit per port
+ if (!_valid_ports)
+ _valid_ports = calloc(num_ports() / 8, 1);
+ lv2_contexts_set_port_valid(_valid_ports, port_index);
+}
+
+
+void*
+NodeBase::valid_ports()
+{
+ return _valid_ports;
+}
+
+
+void
+NodeBase::reset_valid_ports()
+{
+ if (_valid_ports)
+ memset(_valid_ports, '\0', num_ports() / 8);
}
diff --git a/src/engine/NodeBase.hpp b/src/engine/NodeBase.hpp
index 2537039b..15772551 100644
--- a/src/engine/NodeBase.hpp
+++ b/src/engine/NodeBase.hpp
@@ -27,6 +27,7 @@
#include "raul/Atom.hpp"
#include "interface/Port.hpp"
#include "NodeImpl.hpp"
+#include "contexts.lv2/contexts.h"
namespace Ingen {
@@ -70,11 +71,16 @@ public:
virtual void learn() {}
- virtual void message_process(MessageContext& context, uint32_t* ins, uint32_t* outs) {}
+ virtual void message_run(MessageContext& context) {}
- virtual void pre_process(ProcessContext& context);
+ virtual void set_port_valid(uint32_t port_index);
+
+ virtual void* valid_ports();
+ virtual void reset_valid_ports();
+
+ virtual void pre_process(Context& context);
virtual void process(ProcessContext& context) = 0;
- virtual void post_process(ProcessContext& context);
+ virtual void post_process(Context& context);
virtual void set_port_buffer(uint32_t voice, uint32_t port_num, Buffer* buf) {}
@@ -115,15 +121,18 @@ protected:
uint32_t _polyphony;
SampleRate _srate;
size_t _buffer_size;
- bool _activated;
- bool _traversed; ///< Flag for process order algorithm
+ void* _valid_ports; ///< Valid port flags for message context
+
Raul::Semaphore _input_ready; ///< Parallelism: input ready signal
Raul::AtomicInt _process_lock; ///< Parallelism: Waiting on inputs 'lock'
Raul::AtomicInt _n_inputs_ready; ///< Parallelism: # input ready signals this cycle
Raul::Array<PortImpl*>* _ports; ///< Access in audio thread only
Raul::List<NodeImpl*>* _providers; ///< Nodes connected to this one's input ports
Raul::List<NodeImpl*>* _dependants; ///< Nodes this one's output ports are connected to
+
+ bool _activated;
+ bool _traversed; ///< Flag for process order algorithm
};
diff --git a/src/engine/NodeImpl.hpp b/src/engine/NodeImpl.hpp
index 7f3e243a..67ab0898 100644
--- a/src/engine/NodeImpl.hpp
+++ b/src/engine/NodeImpl.hpp
@@ -33,6 +33,7 @@ class PluginImpl;
class PatchImpl;
class PortImpl;
class MessageContext;
+class ProcessContext;
/** A Node (or "module") in a Patch (which is also a Node).
@@ -112,7 +113,16 @@ public:
/** Run the node for one instant in the message thread.
*/
- virtual void message_process(MessageContext& context, uint32_t* ins, uint32_t* outs) = 0;
+ virtual void message_run(MessageContext& context) = 0;
+
+ /** Flag a port as valid (for message context) */
+ virtual void set_port_valid(uint32_t index) = 0;
+
+ /** Return a bit vector of which ports are valid */
+ virtual void* valid_ports() = 0;
+
+ /** Clear all bits in valid_ports() */
+ virtual void reset_valid_ports() = 0;
/** Run the node for @a nframes input/output.
*
diff --git a/src/engine/OSCDriver.hpp b/src/engine/OSCDriver.hpp
index 38eacd48..1c838210 100644
--- a/src/engine/OSCDriver.hpp
+++ b/src/engine/OSCDriver.hpp
@@ -32,7 +32,7 @@ namespace Ingen {
class OSCDriver : public Driver
{
public:
- OSCDriver() : Driver(Shared::DataType::EVENT) {}
+ OSCDriver() : Driver(Shared::DataType::EVENTS) {}
/** Prepare events (however neccessary) for the specified block (realtime safe) */
virtual void prepare_block(const SampleCount block_start, const SampleCount block_end) = 0;
diff --git a/src/engine/ObjectBuffer.cpp b/src/engine/ObjectBuffer.cpp
new file mode 100644
index 00000000..0f40ea9a
--- /dev/null
+++ b/src/engine/ObjectBuffer.cpp
@@ -0,0 +1,119 @@
+/* This file is part of Ingen.
+ * Copyright (C) 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
+ */
+
+#define __STDC_LIMIT_MACROS 1
+#include <string.h>
+#include <stdint.h>
+#include <algorithm>
+#include <iostream>
+#include "uri-map.lv2/uri-map.h"
+#include "ingen-config.h"
+#include "shared/LV2Features.hpp"
+#include "shared/LV2URIMap.hpp"
+#include "ObjectBuffer.hpp"
+#include "Engine.hpp"
+
+using namespace std;
+
+namespace Ingen {
+
+using namespace Shared;
+
+
+/** Allocate a new string buffer.
+ * \a capacity is in bytes.
+ */
+ObjectBuffer::ObjectBuffer(size_t capacity)
+ : Buffer(DataType(DataType::OBJECT), capacity)
+{
+ capacity = std::max(capacity, (size_t)32);
+ cerr << "Creating Object Buffer " << _buf << " capacity = " << capacity << endl;
+ _local_buf = (LV2_Object*)malloc(sizeof(LV2_Object) + capacity);
+ _buf = _local_buf;
+ clear();
+}
+
+
+void
+ObjectBuffer::clear()
+{
+ // nil
+ _buf->type = 0;
+ _buf->size = 0;
+}
+
+
+/** Use another buffer's data instead of the local one.
+ *
+ * This buffer will essentially be identical to @a buf after this call.
+ */
+bool
+ObjectBuffer::join(Buffer* buf)
+{
+ assert(buf != this);
+ ObjectBuffer* sbuf = dynamic_cast<ObjectBuffer*>(buf);
+ if (!sbuf)
+ return false;
+
+ _buf = sbuf->_local_buf;
+ _joined_buf = sbuf;
+
+ return true;
+}
+
+
+void
+ObjectBuffer::unjoin()
+{
+ _joined_buf = NULL;
+ _buf = _local_buf;
+}
+
+
+void
+ObjectBuffer::copy(Context& context, const Buffer* src_buf)
+{
+ const ObjectBuffer* src = dynamic_cast<const ObjectBuffer*>(src_buf);
+ if (!src || src == this || src->_buf == _buf)
+ return;
+
+ // Copy if src is a POD object only, that fits
+ if (src->_buf->type != 0 && src->_buf->size <= size())
+ memcpy(_buf, src->_buf, sizeof(LV2_Object) + src->_buf->size);
+}
+
+
+void
+ObjectBuffer::resize(size_t size)
+{
+ const bool using_local_data = (_buf == _local_buf);
+ const uint32_t contents_size = sizeof(LV2_Object) + _buf->size;
+
+ _local_buf = (LV2_Object*)realloc(_buf, sizeof(LV2_Object) + size);
+ _size = size;
+
+ // If we shrunk and chopped the current contents, clear corrupt data
+ if (size < contents_size)
+ clear();
+
+ if (using_local_data)
+ _buf = _local_buf;
+}
+
+
+} // namespace Ingen
+
diff --git a/src/engine/StringBuffer.hpp b/src/engine/ObjectBuffer.hpp
index 79d83f7a..a1d198e9 100644
--- a/src/engine/StringBuffer.hpp
+++ b/src/engine/ObjectBuffer.hpp
@@ -15,45 +15,43 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef STRINGBUFFER_H
-#define STRINGBUFFER_H
+#ifndef OBJECTBUFFER_H
+#define OBJECTBUFFER_H
-#include "string-port.lv2/string-port.h"
+#include "raul/Atom.hpp"
+#include "object.lv2/object.h"
#include "interface/DataType.hpp"
#include "Buffer.hpp"
namespace Ingen {
+class Context;
-class StringBuffer : public Buffer {
+class ObjectBuffer : public Buffer {
public:
- StringBuffer(size_t capacity);
+ ObjectBuffer(size_t capacity);
void clear();
- void* raw_data() { return (void*)&_buf; }
- const void* raw_data() const { return (void*)&_buf; }
+ void* raw_data() { return (void*)_buf; }
+ const void* raw_data() const { return (void*)_buf; }
- char* data() { return _buf->data; }
- const char* data() const { return _buf->data; }
-
- void prepare_read(FrameTime start, SampleCount nframes);
- void prepare_write(FrameTime start, SampleCount nframes);
+ LV2_Object* data() { return _buf; }
+ const LV2_Object* data() const { return _buf; }
bool join(Buffer* buf);
void unjoin();
- void copy(const Buffer* src, size_t start_sample, size_t end_sample);
+ void copy(Context& context, const Buffer* src);
void resize(size_t size);
private:
- LV2_String_Data* _buf; ///< Contents (_local_buf or belongs to _joined_buf)
- LV2_String_Data _local_buf; ///< Local contents
- uint32_t _this_nframes; ///< Current cycle nframes
+ LV2_Object* _buf; ///< Contents (_local_buf or belongs to _joined_buf)
+ LV2_Object* _local_buf; ///< Local contents
};
} // namespace Ingen
-#endif // STRINGBUFFER_H
+#endif // OBJECTBUFFER_H
diff --git a/src/engine/OutputPort.cpp b/src/engine/OutputPort.cpp
index 023d5a21..8f6b7751 100644
--- a/src/engine/OutputPort.cpp
+++ b/src/engine/OutputPort.cpp
@@ -47,18 +47,18 @@ OutputPort::OutputPort(NodeImpl* parent,
void
-OutputPort::pre_process(ProcessContext& context)
+OutputPort::pre_process(Context& context)
{
for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_write(context.start(), context.nframes());
+ buffer(i)->prepare_write(context);
}
void
-OutputPort::post_process(ProcessContext& context)
+OutputPort::post_process(Context& context)
{
for (uint32_t i=0; i < _poly; ++i)
- buffer(i)->prepare_read(context.start(), context.nframes());
+ buffer(i)->prepare_read(context);
//cerr << path() << " output post: buffer: " << buffer(0) << endl;
diff --git a/src/engine/OutputPort.hpp b/src/engine/OutputPort.hpp
index e5c4ed28..15382332 100644
--- a/src/engine/OutputPort.hpp
+++ b/src/engine/OutputPort.hpp
@@ -47,8 +47,8 @@ public:
const Raul::Atom& value,
size_t buffer_size);
- void pre_process(ProcessContext& context);
- void post_process(ProcessContext& context);
+ void pre_process(Context& context);
+ void post_process(Context& context);
virtual ~OutputPort() {}
diff --git a/src/engine/PatchImpl.hpp b/src/engine/PatchImpl.hpp
index 86133971..8bdbd21a 100644
--- a/src/engine/PatchImpl.hpp
+++ b/src/engine/PatchImpl.hpp
@@ -34,6 +34,7 @@ namespace Shared { class Connection; }
class ConnectionImpl;
class Engine;
class CompiledPatch;
+class ProcessContext;
/** A group of nodes in a graph, possibly polyphonic.
diff --git a/src/engine/PortImpl.cpp b/src/engine/PortImpl.cpp
index 7559ae02..20d0b682 100644
--- a/src/engine/PortImpl.cpp
+++ b/src/engine/PortImpl.cpp
@@ -23,10 +23,12 @@
#include "events/SendPortActivity.hpp"
#include "AudioBuffer.hpp"
#include "EventBuffer.hpp"
+#include "Engine.hpp"
+#include "LV2Object.hpp"
#include "NodeImpl.hpp"
+#include "ObjectBuffer.hpp"
#include "PortImpl.hpp"
#include "ProcessContext.hpp"
-#include "StringBuffer.hpp"
using namespace std;
using namespace Raul;
@@ -69,7 +71,7 @@ PortImpl::PortImpl(NodeImpl* const node,
add_property("rdf:type", Atom(Atom::URI, type.uri()));
- if (type == DataType::EVENT)
+ if (type == DataType::EVENTS)
_broadcast = true; // send activity blips
assert(_buffers->size() > 0);
@@ -176,7 +178,7 @@ PortImpl::clear_buffers()
void
-PortImpl::broadcast_value(ProcessContext& context, bool force)
+PortImpl::broadcast_value(Context& context, bool force)
{
Raul::Atom val;
switch (_type.symbol()) {
@@ -186,14 +188,14 @@ PortImpl::broadcast_value(ProcessContext& context, bool force)
case DataType::CONTROL:
val = ((AudioBuffer*)buffer(0))->value_at(0);
break;
- case DataType::EVENT:
+ case DataType::EVENTS:
if (((EventBuffer*)buffer(0))->event_count() > 0) {
const Events::SendPortActivity ev(context.engine(), context.start(), this);
context.event_sink().write(sizeof(ev), &ev);
}
break;
- case DataType::STRING:
- val = Raul::Atom(((StringBuffer*)buffer(0))->data());
+ case DataType::OBJECT:
+ LV2Object::to_atom(context.engine().world(), ((ObjectBuffer*)buffer(0))->data(), val);
break;
}
diff --git a/src/engine/PortImpl.hpp b/src/engine/PortImpl.hpp
index 7d587165..b9c8dc52 100644
--- a/src/engine/PortImpl.hpp
+++ b/src/engine/PortImpl.hpp
@@ -87,12 +87,13 @@ public:
}
/** Called once per process cycle */
- virtual void pre_process(ProcessContext& context) = 0;
+ virtual void pre_process(Context& context) = 0;
virtual void process(ProcessContext& context) {};
- virtual void post_process(ProcessContext& context) = 0;
+ virtual void post_process(Context& context) = 0;
/** Empty buffer contents completely (ie silence) */
virtual void clear_buffers();
+ virtual void connect_buffers();
virtual bool is_input() const = 0;
virtual bool is_output() const = 0;
@@ -112,7 +113,7 @@ public:
void broadcast(bool b) { _broadcast = b; }
bool broadcast() { return _broadcast; }
- void broadcast_value(ProcessContext& context, bool force=false);
+ void broadcast_value(Context& context, bool force=false);
void raise_set_by_user_flag() { _set_by_user = true; }
@@ -129,7 +130,6 @@ protected:
size_t buffer_size);
virtual void allocate_buffers();
- virtual void connect_buffers();
uint32_t _index;
uint32_t _poly;
diff --git a/src/engine/ProcessContext.hpp b/src/engine/ProcessContext.hpp
index a5c8149a..743b72c4 100644
--- a/src/engine/ProcessContext.hpp
+++ b/src/engine/ProcessContext.hpp
@@ -42,26 +42,22 @@ class ProcessContext : public Context
public:
ProcessContext(Engine& engine)
: Context(engine, AUDIO)
- , _event_sink(engine, 1024) // FIXME: size?
+ , _nframes(0)
+ , _end(0)
{}
void set_time_slice(SampleCount nframes, FrameTime start, FrameTime end) {
+ locate(start);
_nframes = nframes;
- _start = start;
_end = end;
}
- inline SampleCount nframes() const { return _nframes; }
- inline FrameTime start() const { return _start; }
- inline FrameTime end() const { return _end; }
- inline const EventSink& event_sink() const { return _event_sink; }
- inline EventSink& event_sink() { return _event_sink; }
+ inline SampleCount nframes()const { return _nframes; }
+ inline FrameTime end() const { return _end; }
private:
- SampleCount _nframes; ///< Number of actual time (Jack) frames this cycle
- FrameTime _start; ///< Start frame of this cycle, timeline relative
- FrameTime _end; ///< End frame of this cycle, timeline relative
- EventSink _event_sink; ///< Sink for events generated in the audio thread
+ SampleCount _nframes; ///< Length of this cycle in frames
+ FrameTime _end; ///< End frame of this cycle, timeline relative
};
diff --git a/src/engine/QueuedEngineInterface.cpp b/src/engine/QueuedEngineInterface.cpp
index d2ff74df..55e02206 100644
--- a/src/engine/QueuedEngineInterface.cpp
+++ b/src/engine/QueuedEngineInterface.cpp
@@ -158,11 +158,11 @@ QueuedEngineInterface::put(const URI& uri,
bool meta = uri.substr(0, 6) == "meta:#";
URI subject(meta ? (string("path:/") + uri.substr(6)) : uri.str());
- /*cerr << "ENGINE PUT " << subject << " {" << endl;
+ cerr << "ENGINE PUT " << subject << " {" << endl;
typedef Resource::Properties::const_iterator iterator;
for (iterator i = properties.begin(); i != properties.end(); ++i)
cerr << "\t" << i->first << " = " << i->second << " :: " << i->second.type() << endl;
- cerr << "}" << endl;*/
+ cerr << "}" << endl;
push_queued(new Events::SetMetadata(_engine, _responder, now(), this, true, meta, subject, properties));
}
diff --git a/src/engine/StringBuffer.cpp b/src/engine/StringBuffer.cpp
deleted file mode 100644
index a6cec9f1..00000000
--- a/src/engine/StringBuffer.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This file is part of Ingen.
- * Copyright (C) 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
- */
-
-#define __STDC_LIMIT_MACROS 1
-#include <string.h>
-#include <stdint.h>
-#include <iostream>
-#include "ingen-config.h"
-#include "StringBuffer.hpp"
-
-using namespace std;
-
-namespace Ingen {
-
-using namespace Shared;
-
-/** Allocate a new string buffer.
- * \a capacity is in bytes.
- */
-StringBuffer::StringBuffer(size_t capacity)
- : Buffer(DataType(DataType::EVENT), capacity)
-{
- memset(&_local_buf, '\0', sizeof(LV2_String_Data));
- _local_buf.data = (char*)malloc(capacity);
- _local_buf.storage = capacity;
-
- _buf = &_local_buf;
- clear();
-
- cerr << "Creating String Buffer " << _buf << ", capacity = " << capacity << endl;
-}
-
-
-void
-StringBuffer::clear()
-{
- static const string default_val("2\n0 1\n1 1\n");
- if (_buf && _buf->data && _buf->storage > default_val.length())
- strncpy(_buf->data, default_val.c_str(), default_val.length());
-}
-
-
-/** Use another buffer's data instead of the local one.
- *
- * This buffer will essentially be identical to @a buf after this call.
- */
-bool
-StringBuffer::join(Buffer* buf)
-{
- assert(buf != this);
- StringBuffer* sbuf = dynamic_cast<StringBuffer*>(buf);
- if (!sbuf)
- return false;
-
- _buf = &sbuf->_local_buf;
- _joined_buf = sbuf;
-
- return true;
-}
-
-
-void
-StringBuffer::unjoin()
-{
- _joined_buf = NULL;
- _buf = &_local_buf;
-}
-
-
-void
-StringBuffer::prepare_read(FrameTime start, SampleCount nframes)
-{
- _this_nframes = nframes;
-}
-
-
-void
-StringBuffer::prepare_write(FrameTime start, SampleCount nframes)
-{
-}
-
-
-void
-StringBuffer::copy(const Buffer* src_buf, size_t start_sample, size_t end_sample)
-{
- const StringBuffer* src = dynamic_cast<const StringBuffer*>(src_buf);
- assert(src);
- assert(src != this);
- assert(src->_buf != _buf);
- assert(src->_buf->data != _buf->data);
-
- strncpy(_buf->data, src->_buf->data, std::min(_buf->len, src->_buf->len));
- _this_nframes = end_sample - start_sample;
-}
-
-
-void
-StringBuffer::resize(size_t size)
-{
- _buf->data = (char*)realloc(_buf->data, size);
- _buf->storage = size;
- _size = size;
-}
-
-
-} // namespace Ingen
-
diff --git a/src/engine/events/ClearPatch.cpp b/src/engine/events/ClearPatch.cpp
index 3957294e..92c0156c 100644
--- a/src/engine/events/ClearPatch.cpp
+++ b/src/engine/events/ClearPatch.cpp
@@ -117,7 +117,7 @@ ClearPatch::execute(ProcessContext& context)
if (port && port->type() == DataType::AUDIO) {
_driver_ports->push_back(
_engine.audio_driver()->remove_port(port->path()));
- } else if (port && port->type() == DataType::EVENT) {
+ } else if (port && port->type() == DataType::EVENTS) {
_driver_ports->push_back(
_engine.midi_driver()->remove_port(port->path()));
}
diff --git a/src/engine/events/Delete.cpp b/src/engine/events/Delete.cpp
index d8a8bef9..aa773176 100644
--- a/src/engine/events/Delete.cpp
+++ b/src/engine/events/Delete.cpp
@@ -155,7 +155,7 @@ Delete::execute(ProcessContext& context)
if ( ! _port->parent_patch()->parent()) {
if (_port->type() == DataType::AUDIO)
_driver_port = _engine.audio_driver()->remove_port(_port->path());
- else if (_port->type() == DataType::EVENT)
+ else if (_port->type() == DataType::EVENTS)
_driver_port = _engine.midi_driver()->remove_port(_port->path());
// Apparently this needs to be called in post_process??
diff --git a/src/engine/events/Move.cpp b/src/engine/events/Move.cpp
index 1b12819e..9782e0d6 100644
--- a/src/engine/events/Move.cpp
+++ b/src/engine/events/Move.cpp
@@ -108,7 +108,7 @@ Move::execute(ProcessContext& context)
if (port->type() == DataType::AUDIO)
driver_port = _engine.audio_driver()->driver_port(_new_path);
- else if (port->type() == DataType::EVENT)
+ else if (port->type() == DataType::EVENTS)
driver_port = _engine.midi_driver()->driver_port(_new_path);
if (driver_port)
diff --git a/src/engine/events/RequestMetadata.cpp b/src/engine/events/RequestMetadata.cpp
index e633ca10..06069f74 100644
--- a/src/engine/events/RequestMetadata.cpp
+++ b/src/engine/events/RequestMetadata.cpp
@@ -17,15 +17,17 @@
#include "interface/ClientInterface.hpp"
#include "events/RequestMetadata.hpp"
-#include "Responder.hpp"
+#include "shared/LV2Object.hpp"
+#include "AudioBuffer.hpp"
+#include "ClientBroadcaster.hpp"
#include "Engine.hpp"
-#include "GraphObjectImpl.hpp"
#include "EngineStore.hpp"
-#include "ClientBroadcaster.hpp"
-#include "PortImpl.hpp"
+#include "GraphObjectImpl.hpp"
+#include "ObjectBuffer.hpp"
#include "PluginImpl.hpp"
-#include "AudioBuffer.hpp"
-#include "StringBuffer.hpp"
+#include "PortImpl.hpp"
+#include "ProcessContext.hpp"
+#include "Responder.hpp"
using namespace std;
using namespace Raul;
@@ -94,8 +96,9 @@ RequestMetadata::execute(ProcessContext& context)
if (port) {
if (port->type() == DataType::CONTROL || port->type() == DataType::AUDIO)
_value = ((AudioBuffer*)port->buffer(0))->value_at(0); // TODO: offset
- else if (port->type() == DataType::STRING)
- _value = (char*)((StringBuffer*)port->buffer(0))->data();
+ else if (port->type() == DataType::OBJECT)
+ LV2Object::to_atom(context.engine().world(),
+ ((ObjectBuffer*)port->buffer(0))->data(), _value);
} else {
_resource = 0;
}
diff --git a/src/engine/events/SetPortValue.cpp b/src/engine/events/SetPortValue.cpp
index 1964880d..6b9d8d9e 100644
--- a/src/engine/events/SetPortValue.cpp
+++ b/src/engine/events/SetPortValue.cpp
@@ -19,6 +19,7 @@
#include "event.lv2/event.h"
#include "shared/LV2URIMap.hpp"
#include "shared/LV2Features.hpp"
+#include "shared/LV2Object.hpp"
#include "module/World.hpp"
#include "AudioBuffer.hpp"
#include "ClientBroadcaster.hpp"
@@ -27,11 +28,11 @@
#include "EventBuffer.hpp"
#include "MessageContext.hpp"
#include "NodeImpl.hpp"
+#include "ObjectBuffer.hpp"
#include "PortImpl.hpp"
#include "ProcessContext.hpp"
#include "Responder.hpp"
#include "SetPortValue.hpp"
-#include "StringBuffer.hpp"
using namespace std;
using namespace Raul;
@@ -115,7 +116,8 @@ SetPortValue::pre_process()
// Port is a message context port, set its value and
// call the plugin's message run function once
if (_port && _port->context() == Context::MESSAGE) {
- apply(0, 0);
+ apply(*_engine.message_context());
+ _port->parent_node()->set_port_valid(_port->index());
_engine.message_context()->run(_port->parent_node());
}
@@ -132,13 +134,14 @@ SetPortValue::execute(ProcessContext& context)
if (_port && _port->context() == Context::MESSAGE)
return;
- apply(context.start(), context.nframes());
+ apply(context);
}
void
-SetPortValue::apply(uint32_t start, uint32_t nframes)
+SetPortValue::apply(Context& context)
{
+ uint32_t start = context.start();
if (_error == NO_ERROR && !_port)
_port = _engine.engine_store()->find_port(_port_path);
@@ -170,15 +173,12 @@ SetPortValue::apply(uint32_t start, uint32_t nframes)
return;
}
- const LV2Features::Feature* f = _engine.world()->lv2_features->feature(LV2_URI_MAP_URI);
- LV2URIMap* map = (LV2URIMap*)f->controller;
+ SharedPtr<LV2URIMap> map = PtrCast<LV2URIMap>(
+ _engine.world()->lv2_features->feature(LV2_URI_MAP_URI));
- // TODO: eliminate lookups
EventBuffer* const ebuf = dynamic_cast<EventBuffer*>(buf);
if (ebuf) {
- const uint32_t frames = std::max(
- uint32_t(_time - start),
- ebuf->latest_frames());
+ const uint32_t frames = std::max(uint32_t(_time - start), ebuf->latest_frames());
// Size 0 event, pass it along to the plugin as a typed but empty event
if (_value.data_size() == 0) {
@@ -188,34 +188,27 @@ SetPortValue::apply(uint32_t start, uint32_t nframes)
return;
} else if (!strcmp(_value.get_blob_type(), "lv2midi:MidiEvent")) {
- const uint32_t type_id = map->uri_to_id(NULL,
- "http://lv2plug.in/ns/ext/midi#MidiEvent");
-
- ebuf->prepare_write(start, nframes);
- // FIXME: use OSC midi type? avoid MIDI over OSC entirely?
- ebuf->append(frames, 0, type_id, _value.data_size(),
+ ebuf->prepare_write(context);
+ ebuf->append(frames, 0, map->midi_event, _value.data_size(),
(const uint8_t*)_value.get_blob());
_port->raise_set_by_user_flag();
return;
}
}
- StringBuffer* const sbuf = dynamic_cast<StringBuffer*>(buf);
- if (sbuf) {
- if (_value.type() != Atom::STRING) {
- _error = TYPE_MISMATCH;
+ ObjectBuffer* const obuf = dynamic_cast<ObjectBuffer*>(buf);
+ if (obuf) {
+ obuf->data()->size = obuf->size() - sizeof(LV2_Object);
+ if (LV2Object::from_atom(_engine.world(), _value, obuf->data())) {
+ cout << "Converted atom " << _value << " :: " << obuf->data()->type
+ << " * " << obuf->data()->size << " @ " << obuf->data() << endl;
return;
+ } else {
+ cerr << "WARNING: Failed to convert atom to LV2 object" << endl;
}
- strncpy(sbuf->data(), _value.get_string(),
- std::min(sbuf->size(), strlen(_value.get_string())));
- return;
}
-
- if (_value.type() == Atom::BLOB)
- cerr << "WARNING: Unknown value blob type " << _value.get_blob_type() << endl;
- else
- cerr << "WARNING: Unknown value type " << (int)_value.type() << endl;
+ cerr << "WARNING: Unknown value type " << (int)_value.type() << endl;
}
}
diff --git a/src/engine/events/SetPortValue.hpp b/src/engine/events/SetPortValue.hpp
index 87f4f6f6..aab59811 100644
--- a/src/engine/events/SetPortValue.hpp
+++ b/src/engine/events/SetPortValue.hpp
@@ -77,7 +77,7 @@ private:
TYPE_MISMATCH
};
- void apply(uint32_t start, uint32_t nframes);
+ void apply(Context& context);
bool _queued;
bool _omni;
diff --git a/src/engine/internals/Controller.cpp b/src/engine/internals/Controller.cpp
index 70d1e7a9..9788206e 100644
--- a/src/engine/internals/Controller.cpp
+++ b/src/engine/internals/Controller.cpp
@@ -48,7 +48,7 @@ ControllerNode::ControllerNode(const string& path,
{
_ports = new Raul::Array<PortImpl*>(6);
- _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENT, Raul::Atom(), _buffer_size);
+ _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENTS, Raul::Atom(), _buffer_size);
_ports->at(0) = _midi_in_port;
_param_port = new InputPort(this, "controller", 1, 1, DataType::CONTROL, 0.0f, 1);
@@ -84,7 +84,6 @@ ControllerNode::process(ProcessContext& context)
uint8_t* buf = NULL;
EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0);
- //assert(midi_in->this_nframes() == context.nframes());
midi_in->rewind();
diff --git a/src/engine/internals/Note.cpp b/src/engine/internals/Note.cpp
index 1a7d3f5e..4dc11891 100644
--- a/src/engine/internals/Note.cpp
+++ b/src/engine/internals/Note.cpp
@@ -48,7 +48,7 @@ NoteNode::NoteNode(const string& path, bool polyphonic, PatchImpl* parent, Sampl
{
_ports = new Raul::Array<PortImpl*>(5);
- _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENT, Raul::Atom(), _buffer_size);
+ _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENTS, Raul::Atom(), _buffer_size);
_ports->at(0) = _midi_in_port;
_freq_port = new OutputPort(this, "frequency", 1, _polyphony, DataType::AUDIO, 440.0f, _buffer_size);
@@ -126,8 +126,6 @@ NoteNode::process(ProcessContext& context)
uint16_t size = 0;
uint8_t* buf = NULL;
- //assert(midi_in->this_nframes() == context.nframes());
-
midi_in->rewind();
if (midi_in->event_count() > 0)
diff --git a/src/engine/internals/Trigger.cpp b/src/engine/internals/Trigger.cpp
index d30873c9..428a1b8f 100644
--- a/src/engine/internals/Trigger.cpp
+++ b/src/engine/internals/Trigger.cpp
@@ -41,7 +41,7 @@ TriggerNode::TriggerNode(const string& path, bool polyphonic, PatchImpl* parent,
{
_ports = new Raul::Array<PortImpl*>(5);
- _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENT, Raul::Atom(), _buffer_size);
+ _midi_in_port = new InputPort(this, "input", 0, 1, DataType::EVENTS, Raul::Atom(), _buffer_size);
_ports->at(0) = _midi_in_port;
_note_port = new InputPort(this, "note", 1, 1, DataType::CONTROL, 60.0f, 1);
@@ -77,7 +77,6 @@ TriggerNode::process(ProcessContext& context)
uint8_t* buf = NULL;
EventBuffer* const midi_in = (EventBuffer*)_midi_in_port->buffer(0);
- //assert(midi_in->this_nframes() == context.nframes());
midi_in->rewind();
diff --git a/src/engine/wscript b/src/engine/wscript
index 0b3888f0..232fb281 100644
--- a/src/engine/wscript
+++ b/src/engine/wscript
@@ -20,6 +20,7 @@ def build(bld):
MessageContext.cpp
NodeBase.cpp
NodeFactory.cpp
+ ObjectBuffer.cpp
ObjectSender.cpp
OutputPort.cpp
PatchImpl.cpp
@@ -28,7 +29,6 @@ def build(bld):
PostProcessor.cpp
ProcessSlave.cpp
QueuedEvent.cpp
- StringBuffer.cpp
events/SendPortActivity.cpp
events/SendPortValue.cpp
ingen_engine.cpp
diff --git a/src/gui/Configuration.cpp b/src/gui/Configuration.cpp
index c7a5b19c..58a2abc5 100644
--- a/src/gui/Configuration.cpp
+++ b/src/gui/Configuration.cpp
@@ -41,7 +41,7 @@ Configuration::Configuration()
, _control_port_color(0x4A8A0EC0)
, _event_port_color( 0x960909C0)
// , _osc_port_color( 0x5C3566C0)
- , _string_port_color( 0x00000000)
+ , _object_port_color( 0x5C3566C0)
{
}
@@ -90,12 +90,12 @@ Configuration::get_port_color(const PortModel* p)
return _control_port_color;
} else if (p->type().is_audio()) {
return _audio_port_color;
- } else if (p->type().is_event()) {
+ } else if (p->type().is_events()) {
return _event_port_color;
/*} else if (p->type().is_osc()) {
return _osc_port_color;
- */} else if (p->type().is_string()) {
- return _string_port_color;
+ */} else if (p->type().is_object()) {
+ return _object_port_color;
}
cerr << "[Configuration] Unknown port type " << p->type().uri()
diff --git a/src/gui/Configuration.hpp b/src/gui/Configuration.hpp
index 480ed6d1..f66d9f67 100644
--- a/src/gui/Configuration.hpp
+++ b/src/gui/Configuration.hpp
@@ -68,7 +68,7 @@ private:
uint32_t _audio_port_color;
uint32_t _control_port_color;
uint32_t _event_port_color;
- uint32_t _string_port_color;
+ uint32_t _object_port_color;
};
diff --git a/src/gui/ControlPanel.cpp b/src/gui/ControlPanel.cpp
index 1e7d177b..95cd6e02 100644
--- a/src/gui/ControlPanel.cpp
+++ b/src/gui/ControlPanel.cpp
@@ -120,7 +120,7 @@ ControlPanel::add_port(SharedPtr<PortModel> pm)
Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference("toggle_control");
xml->get_widget_derived("toggle_control", tc);
control = tc;
- } else if (pm->type().is_string()) {
+ } else if (pm->type().is_object()) {
StringControl* sc;
Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference("string_control");
xml->get_widget_derived("string_control", sc);
diff --git a/src/gui/Controls.cpp b/src/gui/Controls.cpp
index 6ab9081a..6e8ca351 100644
--- a/src/gui/Controls.cpp
+++ b/src/gui/Controls.cpp
@@ -414,16 +414,16 @@ ToggleControl::set_value(const Atom& val)
{
bool enable = false;
switch (val.type()) {
- case Atom::FLOAT:
- enable = (val.get_float() != 0.0f);
- break;
- case Atom::INT:
- enable = (val.get_int32() != 0);
- break;
- case Atom::BOOL:
- enable = (val.get_bool());
- default:
- cerr << "Unsupported value type for toggle control" << endl;
+ case Atom::FLOAT:
+ enable = (val.get_float() != 0.0f);
+ break;
+ case Atom::INT:
+ enable = (val.get_int32() != 0);
+ break;
+ case Atom::BOOL:
+ enable = (val.get_bool());
+ default:
+ cerr << "Unsupported value type for toggle control" << endl;
}
_enable_signal = false;
@@ -521,11 +521,9 @@ StringControl::disable()
void
StringControl::activated()
{
- if (_enable_signal) {
- const string& value = _entry->get_text();
- cerr << "String control activated: " << value << endl;
- _control_panel->value_changed(_port_model, value.c_str());
- }
+ if (_enable_signal)
+ _control_panel->value_changed_atom(_port_model,
+ Raul::Atom(_entry->get_text().c_str()));
}
diff --git a/src/gui/PatchCanvas.cpp b/src/gui/PatchCanvas.cpp
index c7e3559c..0f071334 100644
--- a/src/gui/PatchCanvas.cpp
+++ b/src/gui/PatchCanvas.cpp
@@ -496,7 +496,7 @@ PatchCanvas::connect(boost::shared_ptr<FlowCanvas::Connectable> src_port,
return;
// Midi binding/learn shortcut
- if (src->model()->type().is_event() && dst->model()->type().is_control()) {
+ if (src->model()->type().is_events() && dst->model()->type().is_control()) {
cerr << "[PatchCanvas] TODO: MIDI binding shortcut" << endl;
} else {
App::instance().engine()->connect(src->model()->path(), dst->model()->path());
diff --git a/src/gui/Port.cpp b/src/gui/Port.cpp
index ddefd0e2..c4f5de5e 100644
--- a/src/gui/Port.cpp
+++ b/src/gui/Port.cpp
@@ -127,7 +127,7 @@ Port::set_control(float value, bool signal)
if (signal) {
if (model()->type() == DataType::CONTROL) {
App::instance().engine()->set_port_value(model()->path(), Atom(value));
- } else if (model()->type() == DataType::EVENT) {
+ } else if (model()->type() == DataType::EVENTS) {
App::instance().engine()->set_port_value(model()->path(),
Atom("<http://example.org/ev#BangEvent>", 0, NULL));
}
diff --git a/src/gui/PortMenu.cpp b/src/gui/PortMenu.cpp
index c6229361..8a98b281 100644
--- a/src/gui/PortMenu.cpp
+++ b/src/gui/PortMenu.cpp
@@ -48,7 +48,7 @@ PortMenu::init(SharedPtr<PortModel> port, bool patch_port)
_destroy_menuitem->hide();
}
- if (port->type() == DataType::EVENT || port->type() == DataType::STRING)
+ if (port->type() == DataType::EVENTS || port->type() == DataType::OBJECT)
_polyphonic_menuitem->hide();
_enable_signal = true;
diff --git a/src/shared/LV2Features.cpp b/src/shared/LV2Features.cpp
index d21462c9..b57f1117 100644
--- a/src/shared/LV2Features.cpp
+++ b/src/shared/LV2Features.cpp
@@ -16,6 +16,7 @@
*/
#include <cstdlib>
+#include <cstring>
#include "LV2Features.hpp"
#include "LV2URIMap.hpp"
@@ -26,39 +27,39 @@ namespace Shared {
LV2Features::LV2Features()
- : _lv2_features((LV2_Feature**)malloc(sizeof(LV2_Feature*)))
+// : _lv2_features((LV2_Feature**)malloc(sizeof(LV2_Feature*)))
{
- _lv2_features[0] = NULL;
+// _lv2_features[0] = NULL;
- LV2URIMap* controller = new LV2URIMap();
- add_feature(LV2_URI_MAP_URI, controller->feature(), controller);
+ add_feature(LV2_URI_MAP_URI, SharedPtr<Feature>(new LV2URIMap()));
}
-const LV2Features::Feature*
+SharedPtr<LV2Features::Feature>
LV2Features::feature(const std::string& uri)
{
Features::const_iterator i = _features.find(uri);
if (i != _features.end())
- return &i->second;
+ return i->second;
else
- return NULL;
+ return SharedPtr<Feature>();
}
void
-LV2Features::add_feature(const std::string& uri, LV2_Feature* feature, void* controller)
+LV2Features::add_feature(const std::string& uri, SharedPtr<Feature> feature)
{
-#ifndef NDEBUG
- Features::const_iterator i = _features.find(uri);
- assert(i == _features.end());
- assert(_lv2_features[_features.size()] == NULL);
-#endif
- _features.insert(make_pair(uri, Feature(feature, controller)));
+ _features.insert(make_pair(uri, feature));
+}
- _lv2_features = (LV2_Feature**)realloc(_lv2_features, sizeof(LV2_Feature*) * (_features.size() + 1));
- _lv2_features[_features.size()-1] = feature;
- _lv2_features[_features.size()] = NULL;
+
+SharedPtr<LV2Features::FeatureArray>
+LV2Features::lv2_features(Node* node) const
+{
+ FeatureArray::FeatureVector vec;
+ for (Features::const_iterator f = _features.begin(); f != _features.end(); ++f)
+ vec.push_back(f->second->feature(node));
+ return SharedPtr<FeatureArray>(new FeatureArray(vec));
}
diff --git a/src/shared/LV2Features.hpp b/src/shared/LV2Features.hpp
index f2299c5c..78d467a5 100644
--- a/src/shared/LV2Features.hpp
+++ b/src/shared/LV2Features.hpp
@@ -25,11 +25,14 @@
#include <map>
#include <string>
+#include <vector>
#include "slv2/slv2.h"
+#include "raul/SharedPtr.hpp"
namespace Ingen {
namespace Shared {
+class Node;
/** Stuff that may need to be passed to an LV2 plugin (i.e. LV2 features).
*/
@@ -37,26 +40,47 @@ class LV2Features {
public:
LV2Features();
- struct Feature {
- Feature(LV2_Feature* f, void* c=NULL) : feature(f), controller(c) {}
- LV2_Feature* feature; ///< LV2 feature struct (plugin exposed)
- void* controller; ///< Ingen internals, not exposed to plugin
+ class Feature {
+ public:
+ virtual ~Feature() {}
+ virtual SharedPtr<LV2_Feature> feature(Node* node) = 0;
};
- typedef std::map<std::string, Feature> Features;
+ class FeatureArray {
+ public:
+ typedef std::vector< SharedPtr<LV2_Feature> > FeatureVector;
- const Feature* feature(const std::string& uri);
+ FeatureArray(FeatureVector& features)
+ : _features(features)
+ {
+ _array = (LV2_Feature**)malloc(sizeof(LV2_Feature) * (features.size() + 1));
+ _array[features.size()] = NULL;
+ for (size_t i = 0; i < features.size(); ++i)
+ _array[i] = features[i].get();
+ }
- void add_feature(const std::string& uri, LV2_Feature* feature, void* controller);
+ ~FeatureArray() {
+ free(_array);
+ }
- LV2_Feature** lv2_features() const { return _lv2_features; }
+ LV2_Feature** array() { return _array; }
+
+ private:
+ FeatureVector _features;
+ LV2_Feature** _array;
+ };
+
+ SharedPtr<Feature> feature(const std::string& uri);
+
+ void add_feature(const std::string& uri, SharedPtr<Feature> feature);
+
+ SharedPtr<LV2Features::FeatureArray> lv2_features(Node* node) const;
private:
- Features _features;
- LV2_Feature** _lv2_features;
+ typedef std::map< std::string, SharedPtr<Feature> > Features;
+ Features _features;
};
-
} // namespace Shared
} // namespace Ingen
diff --git a/src/shared/LV2Object.cpp b/src/shared/LV2Object.cpp
new file mode 100644
index 00000000..3442c004
--- /dev/null
+++ b/src/shared/LV2Object.cpp
@@ -0,0 +1,96 @@
+/* This file is part of Ingen.
+ * Copyright (C) 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 <iostream>
+#include "raul/Atom.hpp"
+#include "module/World.hpp"
+#include "uri-map.lv2/uri-map.h"
+#include "object.lv2/object.h"
+#include "LV2Features.hpp"
+#include "LV2Object.hpp"
+#include "LV2URIMap.hpp"
+
+using namespace std;
+
+namespace Ingen {
+namespace Shared {
+namespace LV2Object {
+
+
+bool
+to_atom(World* world, LV2_Object* object, Raul::Atom& atom)
+{
+ SharedPtr<LV2URIMap> map = PtrCast<LV2URIMap>(world->lv2_features->feature(LV2_URI_MAP_URI));
+
+ if (object->type == map->object_class_string) {
+ atom = Raul::Atom((char*)(object + 1));
+ return true;
+ } else if (object->type == map->object_class_int32) {
+ atom = Raul::Atom((int32_t*)(object + 1));
+ return true;
+ } else if (object->type == map->object_class_float32) {
+ atom = Raul::Atom((float*)(object + 1));
+ return true;
+ }
+ return false;
+}
+
+
+/** Convert an atom to an LV2 object, if possible.
+ * object->size should be the capacity of the object (not including header)
+ */
+bool
+from_atom(World* world, const Raul::Atom& atom, LV2_Object* object)
+{
+ SharedPtr<LV2URIMap> map = PtrCast<LV2URIMap>(world->lv2_features->feature(LV2_URI_MAP_URI));
+
+ char* str;
+ switch (atom.type()) {
+ case Raul::Atom::FLOAT:
+ object->type = map->object_class_float32;
+ object->size = sizeof(float);
+ *(float*)(object + 1) = atom.get_float();
+ break;
+ case Raul::Atom::INT:
+ object->type = map->object_class_int32;
+ object->size = sizeof(int32_t);
+ *(int32_t*)(object + 1) = atom.get_int32();
+ break;
+ case Raul::Atom::STRING:
+ object->type = map->object_class_string;
+ object->size = std::min(object->size, (uint32_t)strlen(atom.get_string()) + 1);
+ str = ((char*)(object + 1));
+ str[object->size - 1] = '\0';
+ strncpy(str, atom.get_string(), object->size);
+ break;
+ case Raul::Atom::BLOB:
+ object->type = map->object_class_string;
+ *(uint32_t*)(object + 1) = map->uri_to_id(NULL, atom.get_blob_type());
+ memcpy(((char*)(object + 1) + sizeof(uint32_t)), atom.get_blob(),
+ std::min(atom.data_size(), (size_t)object->size));
+ default:
+ cerr << "Unsupported value type for toggle control" << endl;
+ return false;
+ }
+ return true;
+}
+
+
+} // namespace LV2Object
+
+} // namespace Shared
+} // namespace Ingen
diff --git a/src/shared/LV2Object.hpp b/src/shared/LV2Object.hpp
new file mode 100644
index 00000000..1e72c4e0
--- /dev/null
+++ b/src/shared/LV2Object.hpp
@@ -0,0 +1,39 @@
+/* This file is part of Ingen.
+ * Copyright (C) 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 LV2_OBJECT_HPP
+#define LV2_OBJECT_HPP
+
+namespace Raul { class Atom; }
+typedef struct _LV2_Object LV2_Object;
+
+namespace Ingen {
+namespace Shared {
+
+class World;
+
+namespace LV2Object {
+
+ bool to_atom(World* world, const LV2_Object* object, Raul::Atom& atom);
+ bool from_atom(World* word, const Raul::Atom& atom, LV2_Object* object);
+
+} // namespace LV2Object
+
+} // namespace Shared
+} // namespace Ingen
+
+#endif // LV2_OBJECT_HPP
diff --git a/src/shared/LV2URIMap.cpp b/src/shared/LV2URIMap.cpp
index e3ab6a48..65e3aa30 100644
--- a/src/shared/LV2URIMap.cpp
+++ b/src/shared/LV2URIMap.cpp
@@ -19,6 +19,7 @@
#include <cassert>
#include <iostream>
#include <stdint.h>
+#include "object.lv2/object.h"
#include "LV2URIMap.hpp"
using namespace std;
@@ -28,7 +29,16 @@ namespace Shared {
LV2URIMap::LV2URIMap()
- : next_uri_id(1)
+ : uri_map()
+ , next_uri_id(1)
+ , object_class_bool(uri_to_id(NULL, LV2_OBJECT_URI "#Bool"))
+ , object_class_string(uri_to_id(NULL, LV2_OBJECT_URI "#String"))
+ , object_class_int32(uri_to_id(NULL, LV2_OBJECT_URI "#Int32"))
+ , object_class_float32(uri_to_id(NULL, LV2_OBJECT_URI "#Float32"))
+ , ui_format_events(uri_to_id(NULL, "http://lv2plug.in/ns/extensions/ui#Events"))
+ , midi_event(uri_to_id(NULL, "http://lv2plug.in/ns/ext/midi#MidiEvent"))
+ , string_transfer(uri_to_id(NULL, "http://lv2plug.in/ns/dev/string-port#StringTransfer"))
+ , object_transfer(uri_to_id(NULL, LV2_OBJECT_URI "#ObjectTransfer"))
{
uri_map_feature_data.uri_to_id = &LV2URIMap::uri_map_uri_to_id;
uri_map_feature_data.callback_data = this;
diff --git a/src/shared/LV2URIMap.hpp b/src/shared/LV2URIMap.hpp
index f1b9c919..0dd6b0cb 100644
--- a/src/shared/LV2URIMap.hpp
+++ b/src/shared/LV2URIMap.hpp
@@ -28,6 +28,7 @@
#include <boost/utility.hpp>
#include "slv2/slv2.h"
#include "uri-map.lv2/uri-map.h"
+#include "LV2Features.hpp"
namespace Ingen {
namespace Shared {
@@ -35,14 +36,15 @@ namespace Shared {
/** Implementation of the LV2 URI Map extension
*/
-class LV2URIMap : public boost::noncopyable {
+class LV2URIMap : public boost::noncopyable, public LV2Features::Feature {
public:
LV2URIMap();
- LV2_Feature* feature() { return &uri_map_feature; }
+ SharedPtr<LV2_Feature> feature(Node*) {
+ return SharedPtr<LV2_Feature>(&uri_map_feature, NullDeleter<LV2_Feature>);
+ }
- uint32_t uri_to_id(const char* map,
- const char* uri);
+ uint32_t uri_to_id(const char* map, const char* uri);
private:
typedef std::map<std::string, uint32_t> URIMap;
@@ -55,6 +57,16 @@ private:
LV2_URI_Map_Feature uri_map_feature_data;
URIMap uri_map;
uint32_t next_uri_id;
+
+public:
+ const uint32_t object_class_bool;
+ const uint32_t object_class_string;
+ const uint32_t object_class_int32;
+ const uint32_t object_class_float32;
+ const uint32_t ui_format_events;
+ const uint32_t midi_event;
+ const uint32_t string_transfer;
+ const uint32_t object_transfer;
};
diff --git a/src/shared/ResourceImpl.cpp b/src/shared/ResourceImpl.cpp
index b4b40116..6d028a13 100644
--- a/src/shared/ResourceImpl.cpp
+++ b/src/shared/ResourceImpl.cpp
@@ -110,10 +110,10 @@ ResourceImpl::type(
port = true;
}
} else if (!strcmp(atom.get_uri(), "lv2ev:EventPort")) {
- data_type = DataType::EVENT;
+ data_type = DataType::EVENTS;
port = true;
- } else if (!strcmp(atom.get_uri(), "sp:StringPort")) {
- data_type = DataType::STRING;
+ } else if (!strcmp(atom.get_uri(), "obj:ObjectPort")) {
+ data_type = DataType::OBJECT;
port = true;
}
}
diff --git a/src/shared/wscript b/src/shared/wscript
index 50fb7320..3f60752c 100644
--- a/src/shared/wscript
+++ b/src/shared/wscript
@@ -7,10 +7,11 @@ def build(bld):
Builder.cpp
ClashAvoider.cpp
LV2Features.cpp
+ LV2Object.cpp
LV2URIMap.cpp
ResourceImpl.cpp
- runtime_paths.cpp
Store.cpp
+ runtime_paths.cpp
'''
if bld.env['HAVE_LIBLO'] == 1:
obj.source += ' OSCSender.cpp '