summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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 '