13
0

Update to latest LV2 atom extension.

git-svn-id: svn://localhost/ardour2/branches/3.0@11548 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2012-02-29 03:21:37 +00:00
parent 9dd4d79d6c
commit 8de887f378
8 changed files with 123 additions and 116 deletions

View File

@ -112,13 +112,13 @@ public:
}
#ifdef LV2_SUPPORT
/** Get a MIDI buffer translated into an LV2 MIDI buffer for use with plugins.
* The index here corresponds directly to MIDI buffer numbers (i.e. the index
* passed to get_midi), translation back and forth will happen as needed.
* If atom_type is 0 the returned buffer will be in the old event API
* format. Otherwise, atom_type must be the URID for atom:Sequence.
/** Get a MIDI buffer translated into an LV2 MIDI buffer for use with
* plugins. The index here corresponds directly to MIDI buffer numbers
* (i.e. the index passed to get_midi), translation back and forth will
* happen as needed. If old_api is true, the returned buffer will be in
* old event format. Otherwise it will be in new atom sequence format.
*/
LV2_Evbuf* get_lv2_midi(bool input, size_t i, uint32_t atom_type);
LV2_Evbuf* get_lv2_midi(bool input, size_t i, bool old_api);
/** Flush modified LV2 event output buffers back to Ardour buffers */
void flush_lv2_midi(bool input, size_t i);

View File

@ -130,6 +130,13 @@ class LV2Plugin : public ARDOUR::Plugin
static URIMap _uri_map;
static uint32_t _midi_event_type_ev;
static uint32_t _midi_event_type;
static uint32_t _chunk_type;
static uint32_t _sequence_type;
static uint32_t _event_transfer_type;
static uint32_t _state_path_type;
private:
struct Impl;
Impl* _impl;
@ -193,12 +200,6 @@ class LV2Plugin : public ARDOUR::Plugin
bool _was_activated;
bool _has_state_interface;
static uint32_t _midi_event_type_ev;
static uint32_t _midi_event_type;
static uint32_t _sequence_type;
static uint32_t _event_transfer_type;
static uint32_t _state_path_type;
const std::string plugin_dir () const;
const std::string scratch_dir () const;
const std::string file_dir () const;

View File

@ -190,8 +190,10 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
if (type == DataType::MIDI && _lv2_buffers.size() < _buffers[type].size() * 2 + 1) {
while (_lv2_buffers.size() < _buffers[type].size() * 2) {
_lv2_buffers.push_back(
std::make_pair(false,
lv2_evbuf_new(buffer_capacity, LV2_EVBUF_EVENT, 0)));
std::make_pair(false, lv2_evbuf_new(buffer_capacity,
LV2_EVBUF_EVENT,
LV2Plugin::_chunk_type,
LV2Plugin::_sequence_type)));
}
}
#endif
@ -251,25 +253,23 @@ BufferSet::get(DataType type, size_t i) const
#ifdef LV2_SUPPORT
LV2_Evbuf*
BufferSet::get_lv2_midi(bool input, size_t i, uint32_t atom_type)
BufferSet::get_lv2_midi(bool input, size_t i, bool old_api)
{
assert(count().get(DataType::MIDI) > i);
MidiBuffer& mbuf = get_midi(i);
LV2Buffers::value_type b = _lv2_buffers.at(i * 2 + (input ? 0 : 1));
LV2_Evbuf* evbuf = b.second;
lv2_evbuf_set_type(evbuf,
atom_type ? LV2_EVBUF_ATOM : LV2_EVBUF_EVENT,
atom_type);
lv2_evbuf_set_type(evbuf, old_api ? LV2_EVBUF_EVENT : LV2_EVBUF_ATOM);
lv2_evbuf_reset(evbuf);
lv2_evbuf_reset(evbuf, input);
if (input) {
DEBUG_TRACE(PBD::DEBUG::LV2,
string_compose("%1 bytes of MIDI waiting @ %2\n",
mbuf.size(), (void*) mbuf.data()));
LV2_Evbuf_Iterator i = lv2_evbuf_begin(evbuf);
const uint32_t type = LV2Plugin::midi_event_type(atom_type == 0);
const uint32_t type = LV2Plugin::midi_event_type(old_api);
for (MidiBuffer::iterator e = mbuf.begin(); e != mbuf.end(); ++e) {
const Evoral::MIDIEvent<framepos_t> ev(*e, false);
#ifndef NDEBUG

View File

@ -33,6 +33,7 @@
#define LV2_ATOM__Beats LV2_ATOM_URI "#Beats"
#define LV2_ATOM__Blank LV2_ATOM_URI "#Blank"
#define LV2_ATOM__Bool LV2_ATOM_URI "#Bool"
#define LV2_ATOM__Chunk LV2_ATOM_URI "#Chunk"
#define LV2_ATOM__Double LV2_ATOM_URI "#Double"
#define LV2_ATOM__Event LV2_ATOM_URI "#Event"
#define LV2_ATOM__Float LV2_ATOM_URI "#Float"
@ -55,6 +56,7 @@
#define LV2_ATOM__Vector LV2_ATOM_URI "#Vector"
#define LV2_ATOM__beatTime LV2_ATOM_URI "#beatTime"
#define LV2_ATOM__bufferType LV2_ATOM_URI "#bufferType"
#define LV2_ATOM__childType LV2_ATOM_URI "#childType"
#define LV2_ATOM__eventTransfer LV2_ATOM_URI "#eventTransfer"
#define LV2_ATOM__frameTime LV2_ATOM_URI "#frameTime"
#define LV2_ATOM__supports LV2_ATOM_URI "#supports"
@ -91,6 +93,12 @@ typedef struct {
uint32_t type; /**< Type of this atom (mapped URI). */
} LV2_Atom;
/** A chunk of memory that may be uninitialized or contain an Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
LV2_Atom body; /**< Body atom header. */
} LV2_Atom_Chunk;
/** An atom:Int32 or atom:Bool. May be cast to LV2_Atom. */
typedef struct {
LV2_Atom atom; /**< Atom header. */
@ -229,29 +237,6 @@ typedef struct {
LV2_Atom_Literal_Body body; /**< Body. */
} LV2_Atom_Sequence;
/**
The contents of an atom:AtomPort buffer.
This contains a pointer to an Atom, which is the data to be
processed/written, as well as additional metadata. This struct may be
augmented in the future to add more metadata fields as they become
necessary. The initial version of this struct contains data, size, and
capacity. Implementations MUST check that any other fields they wish to use
are actually present by comparing the size with the offset of that field,
e.g.:
@code
if (offsetof(LV2_Atom_Port_Buffer, field) < buf->size) {
do_stuff_with(buf->field);
}
@endcode
*/
typedef struct {
LV2_Atom* data; /** Pointer to data. */
uint32_t size; /** Total size of this struct. */
uint32_t capacity; /** Available space for data body. */
} LV2_Atom_Port_Buffer;
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -131,6 +131,7 @@ lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
forge->offset = 0;
forge->sink = NULL;
forge->handle = NULL;
forge->stack = NULL;
}
/**
@ -154,6 +155,7 @@ lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
forge->size = forge->offset = 0;
forge->sink = sink;
forge->handle = handle;
forge->stack = NULL;
}
/**
@ -195,7 +197,7 @@ lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
{
uint8_t* out = NULL;
if (forge->sink) {
out = forge->sink(forge->handle, data, size);
out = (uint8_t*)forge->sink(forge->handle, data, size);
} else {
out = forge->buf + forge->offset;
if (forge->offset + size > forge->size) {
@ -295,12 +297,12 @@ lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
const uint8_t* str,
uint32_t len)
{
uint8_t* out = NULL;
void* out = NULL;
if ( (out = lv2_atom_forge_raw(forge, str, len))
&& (out = lv2_atom_forge_raw(forge, "", 1))) {
lv2_atom_forge_pad(forge, len + 1);
}
return out;
return (uint8_t*)out;
}
/** Write an atom compatible with atom:String. Used internally. */
@ -424,7 +426,7 @@ static inline LV2_Atom_Tuple*
lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
{
const LV2_Atom_Tuple a = { { 0, forge->Tuple } };
LV2_Atom* atom = lv2_atom_forge_write(forge, &a, sizeof(a));
LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a));
return (LV2_Atom_Tuple*)lv2_atom_forge_push(forge, frame, atom);
}

View File

@ -14,8 +14,6 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
@ -27,9 +25,11 @@
struct LV2_Evbuf_Impl {
LV2_Evbuf_Type type;
uint32_t capacity;
uint32_t atom_Chunk;
uint32_t atom_Sequence;
union {
LV2_Event_Buffer event;
LV2_Atom_Port_Buffer atom;
LV2_Event_Buffer event;
LV2_Atom_Sequence atom;
} buf;
};
@ -40,14 +40,19 @@ lv2_evbuf_pad_size(uint32_t size)
}
LV2_Evbuf*
lv2_evbuf_new(uint32_t capacity, LV2_Evbuf_Type type, uint32_t atom_type)
lv2_evbuf_new(uint32_t capacity,
LV2_Evbuf_Type type,
uint32_t atom_Chunk,
uint32_t atom_Sequence)
{
// FIXME: memory must be 64-bit aligned
LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(
sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity);
evbuf->capacity = capacity;
lv2_evbuf_set_type(evbuf, type, atom_type);
lv2_evbuf_reset(evbuf);
evbuf->capacity = capacity;
evbuf->atom_Chunk = atom_Chunk;
evbuf->atom_Sequence = atom_Sequence;
lv2_evbuf_set_type(evbuf, type);
lv2_evbuf_reset(evbuf, true);
return evbuf;
}
@ -58,7 +63,7 @@ lv2_evbuf_free(LV2_Evbuf* evbuf)
}
void
lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type)
lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type)
{
evbuf->type = type;
switch (type) {
@ -67,18 +72,13 @@ lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type)
evbuf->buf.event.capacity = evbuf->capacity;
break;
case LV2_EVBUF_ATOM:
evbuf->buf.atom.data = (LV2_Atom*)(evbuf + 1);
evbuf->buf.atom.size = sizeof(LV2_Atom_Port_Buffer);
evbuf->buf.atom.capacity = evbuf->capacity;
evbuf->buf.atom.data->type = atom_type;
evbuf->buf.atom.data->size = 0;
break;
}
lv2_evbuf_reset(evbuf);
lv2_evbuf_reset(evbuf, true);
}
void
lv2_evbuf_reset(LV2_Evbuf* evbuf)
lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input)
{
switch (evbuf->type) {
case LV2_EVBUF_EVENT:
@ -88,7 +88,13 @@ lv2_evbuf_reset(LV2_Evbuf* evbuf)
evbuf->buf.event.size = 0;
break;
case LV2_EVBUF_ATOM:
evbuf->buf.atom.data->size = 0;
if (input) {
evbuf->buf.atom.atom.size = 0;
evbuf->buf.atom.atom.type = evbuf->atom_Sequence;
} else {
evbuf->buf.atom.atom.size = evbuf->capacity;
evbuf->buf.atom.atom.type = evbuf->atom_Chunk;
}
}
}
@ -99,7 +105,9 @@ lv2_evbuf_get_size(LV2_Evbuf* evbuf)
case LV2_EVBUF_EVENT:
return evbuf->buf.event.size;
case LV2_EVBUF_ATOM:
return evbuf->buf.atom.data->size;
return evbuf->buf.atom.atom.type == evbuf->atom_Sequence
? evbuf->buf.atom.atom.size
: 0;
}
return 0;
}
@ -154,7 +162,7 @@ lv2_evbuf_next(LV2_Evbuf_Iterator iter)
break;
case LV2_EVBUF_ATOM:
size = ((LV2_Atom_Event*)
((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, evbuf->buf.atom.data)
((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, &evbuf->buf.atom)
+ offset))->body.size;
offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
break;
@ -179,10 +187,10 @@ lv2_evbuf_get(LV2_Evbuf_Iterator iter,
return false;
}
LV2_Event_Buffer* ebuf;
LV2_Event* ev;
LV2_Atom_Port_Buffer* abuf;
LV2_Atom_Event* aev;
LV2_Event_Buffer* ebuf;
LV2_Event* ev;
LV2_Atom_Sequence* aseq;
LV2_Atom_Event* aev;
switch (iter.evbuf->type) {
case LV2_EVBUF_EVENT:
ebuf = &iter.evbuf->buf.event;
@ -194,9 +202,9 @@ lv2_evbuf_get(LV2_Evbuf_Iterator iter,
*data = (uint8_t*)ev + sizeof(LV2_Event);
break;
case LV2_EVBUF_ATOM:
abuf = &iter.evbuf->buf.atom;
aseq = (LV2_Atom_Sequence*)&iter.evbuf->buf.atom;
aev = (LV2_Atom_Event*)(
(char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
(char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
+ iter.offset);
*frames = aev->time.frames;
*subframes = 0;
@ -217,10 +225,10 @@ lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
uint32_t size,
const uint8_t* data)
{
LV2_Event_Buffer* ebuf;
LV2_Event* ev;
LV2_Atom_Port_Buffer* abuf;
LV2_Atom_Event* aev;
LV2_Event_Buffer* ebuf;
LV2_Event* ev;
LV2_Atom_Sequence* aseq;
LV2_Atom_Event* aev;
switch (iter->evbuf->type) {
case LV2_EVBUF_EVENT:
ebuf = &iter->evbuf->buf.event;
@ -241,22 +249,23 @@ lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
iter->offset += size;
break;
case LV2_EVBUF_ATOM:
abuf = &iter->evbuf->buf.atom;
if (abuf->capacity - abuf->data->size < sizeof(LV2_Atom_Event) + size) {
aseq = (LV2_Atom_Sequence*)&iter->evbuf->buf.atom;
if (iter->evbuf->capacity - sizeof(LV2_Atom) - aseq->atom.size
< sizeof(LV2_Atom_Event) + size) {
return false;
}
aev = (LV2_Atom_Event*)(
(char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
(char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
+ iter->offset);
aev->time.frames = frames;
aev->body.type = type;
aev->body.size = size;
memcpy(LV2_ATOM_BODY(&aev->body), data, size);
size = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
abuf->data->size += size;
iter->offset += size;
size = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
aseq->atom.size += size;
iter->offset += size;
break;
}

View File

@ -18,10 +18,11 @@
#define LV2_EVBUF_H
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
/**
@ -54,11 +55,13 @@ typedef struct {
/**
Allocate a new, empty event buffer.
The URID for atom:Sequence must be passed for atom_Sequence if type is
LV2_EVBUF_ATOM.
URIDs for atom:Chunk and atom:Sequence must be passed for LV2_EVBUF_ATOM.
*/
LV2_Evbuf*
lv2_evbuf_new(uint32_t capacity, LV2_Evbuf_Type type, uint32_t atom_type);
lv2_evbuf_new(uint32_t capacity,
LV2_Evbuf_Type type,
uint32_t atom_Chunk,
uint32_t atom_Sequence);
/**
Free an event buffer allocated with lv2_evbuf_new.
@ -67,21 +70,21 @@ void
lv2_evbuf_free(LV2_Evbuf* evbuf);
/**
Change the type of an existing event buffer. This will clear and reset the
buffer, it is not possible to change the type and preserve the buffer
contents since the formats differ. The URID for atom:Sequence must be
passed for atom_Sequence if type is LV2_EVBUF_ATOM.
Reset and change the type of an existing event buffer.
URIDs for atom:Chunk and atom:Sequence must be passed for LV2_EVBUF_ATOM.
*/
void
lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type);
lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type);
/**
Clear and initialize an existing event buffer.
The contents of buf are ignored entirely and overwritten, except capacity
which is unmodified.
If input is false and this is an atom buffer, the buffer will be prepared
for writing by the plugin. This MUST be called before every run cycle.
*/
void
lv2_evbuf_reset(LV2_Evbuf* evbuf);
lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input);
/**
Return the total padded size of the events stored in the buffer.

View File

@ -74,6 +74,8 @@ uint32_t LV2Plugin::_midi_event_type_ev = _uri_map.uri_to_id(
uint32_t LV2Plugin::_midi_event_type = _uri_map.uri_to_id(
NULL,
"http://lv2plug.in/ns/ext/midi#MidiEvent");
uint32_t LV2Plugin::_chunk_type = _uri_map.uri_to_id(
NULL, LV2_ATOM__Chunk);
uint32_t LV2Plugin::_sequence_type = _uri_map.uri_to_id(
NULL, LV2_ATOM__Sequence);
uint32_t LV2Plugin::_event_transfer_type = _uri_map.uri_to_id(
@ -88,6 +90,7 @@ public:
LilvWorld* world;
LilvNode* atom_Chunk;
LilvNode* atom_MessagePort;
LilvNode* atom_Sequence;
LilvNode* atom_bufferType;
@ -231,25 +234,7 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
for (uint32_t i = 0; i < num_ports; ++i) {
const LilvPort* port = lilv_plugin_get_port_by_index(_impl->plugin, i);
PortFlags flags = 0;
if (lilv_port_is_a(_impl->plugin, port, _world.lv2_ControlPort)) {
flags |= PORT_CONTROL;
} else if (lilv_port_is_a(_impl->plugin, port, _world.lv2_AudioPort)) {
flags |= PORT_AUDIO;
} else if (lilv_port_is_a(_impl->plugin, port, _world.ev_EventPort)) {
flags |= PORT_EVENT;
} else if (lilv_port_is_a(_impl->plugin, port, _world.atom_MessagePort)) {
LilvNodes* buffer_types = lilv_port_get_value(
_impl->plugin, port, _world.atom_bufferType);
if (lilv_nodes_contains(buffer_types, _world.atom_Sequence)) {
flags |= PORT_MESSAGE;
}
lilv_nodes_free(buffer_types);
} else {
error << string_compose(
"LV2: \"%1\" port %2 has no known data type",
lilv_node_as_string(_impl->name), i) << endmsg;
throw failed_constructor();
}
if (lilv_port_is_a(_impl->plugin, port, _world.lv2_OutputPort)) {
flags |= PORT_OUTPUT;
} else if (lilv_port_is_a(_impl->plugin, port, _world.lv2_InputPort)) {
@ -260,6 +245,27 @@ LV2Plugin::init(void* c_plugin, framecnt_t rate)
lilv_node_as_string(_impl->name), i) << endmsg;
throw failed_constructor();
}
if (lilv_port_is_a(_impl->plugin, port, _world.lv2_ControlPort)) {
flags |= PORT_CONTROL;
} else if (lilv_port_is_a(_impl->plugin, port, _world.lv2_AudioPort)) {
flags |= PORT_AUDIO;
} else if (lilv_port_is_a(_impl->plugin, port, _world.ev_EventPort)) {
flags |= PORT_EVENT;
} else if (lilv_port_is_a(_impl->plugin, port, _world.atom_MessagePort)) {
LilvNodes* buffer_types = lilv_port_get_value(
_impl->plugin, port, _world.atom_bufferType);
if (lilv_nodes_contains(buffer_types, _world.atom_Sequence)) {
flags |= PORT_MESSAGE;
}
lilv_nodes_free(buffer_types);
} else {
error << string_compose(
"LV2: \"%1\" port %2 has no known data type",
lilv_node_as_string(_impl->name), i) << endmsg;
throw failed_constructor();
}
_port_flags.push_back(flags);
}
@ -1097,18 +1103,17 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
be necessary, but the mapping is illegal in some cases. Ideally
that should be fixed, but this is easier...
*/
const uint32_t atom_type = (flags & PORT_MESSAGE) ? _sequence_type : 0;
if (flags & PORT_INPUT) {
index = in_map.get(DataType::MIDI, midi_in_index++, &valid);
_ev_buffers[port_index] = (valid && bufs.count().n_midi() > index)
? bufs.get_lv2_midi(true, index, atom_type)
: silent_bufs.get_lv2_midi(true, 0, atom_type);
? bufs.get_lv2_midi(true, index, flags & PORT_EVENT)
: silent_bufs.get_lv2_midi(true, 0, flags & PORT_EVENT);
buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
} else {
index = out_map.get(DataType::MIDI, midi_out_index++, &valid);
_ev_buffers[port_index] = (valid && bufs.count().n_midi() > index)
? bufs.get_lv2_midi(false, index, atom_type)
: scratch_bufs.get_lv2_midi(false, 0, atom_type);
? bufs.get_lv2_midi(false, index, flags & PORT_EVENT)
: scratch_bufs.get_lv2_midi(false, 0, flags & PORT_EVENT);
buf = lv2_evbuf_get_buffer(_ev_buffers[port_index]);
}
} else {
@ -1313,6 +1318,7 @@ LV2World::LV2World()
: world(lilv_world_new())
{
lilv_world_load_all(world);
atom_Chunk = lilv_new_uri(world, LV2_ATOM__Chunk);
atom_MessagePort = lilv_new_uri(world, LV2_ATOM__MessagePort);
atom_Sequence = lilv_new_uri(world, LV2_ATOM__Sequence);
atom_bufferType = lilv_new_uri(world, LV2_ATOM__bufferType);
@ -1351,6 +1357,7 @@ LV2World::~LV2World()
lilv_node_free(atom_bufferType);
lilv_node_free(atom_Sequence);
lilv_node_free(atom_MessagePort);
lilv_node_free(atom_Chunk);
}
LV2PluginInfo::LV2PluginInfo (void* c_plugin)