On Wed, 2007-11-28 at 23:56 +0100, Lars Luthman wrote:
On Wed, 2007-11-28 at 16:45 +0000, Krzysztof Foltman
wrote:
Good. So let's postpone that part for now, it
will go into different
extension(s).
OK, so what we have now is something like this:
struct Event_Port_Buffer {
uint32_t capacity; // number of elements in the array
uint32_t used_size; // number of _used_ elements
uint32_t event_count; // number of events (different from
// used_size if there are large events -
// would this really be needed?)
struct Event* events; // an array allocated by the host
};
struct Event {
uint32_t timestamp;
uint16_t size;
uint16_t event_type;
uint8_t data[8]; // or a union or whatever, as long
// as it's 8 bytes
};
A pointer to an Event_Port_Buffer is passed to connect_port() for every
event port etc. And in the RDF file for the plugin there would be
something like this:
er, I'm probably missing something here, but why the 8 bytes part?
Isn't that what the size member is for?
<http://myplugin.example.com> a lv2:Plugin;
lv2:requiredFeature <http://lv2.example.com/midi-event-type>;
lv2:port [
a lv2:InputPort, <http://lv2.example.com/event-port>;
...
];
...
Sounds about right. If it's an optional feature, the plugin can just
ignore events of a type it doesn't understand (this should probably be
the default/common case).
The host won't instantiate the plugin unless it
knows how to handle
event ports and MIDI events, and the plugin will fail to instantiate
unless the host passes a URI -> integer map to instantiate using a
LV2_Feature with the URI <http://lv2.example.com/uri-map> and a
NULL-terminated array of event type URIs as data. The integer associated
to each URI is simply the array index (my earlier suggestion was just a
brain dump from a thought-in-progress, a simple array seems a lot
cleaner).
Perfect. As extensible as URIs, as fast as integers, ties in to the
RDF.
Assuming that the host only supports MIDI events the
data passed for
this feature will be { "http://lv2.example.com/midi-event-type", NULL },
the plugin will store the index 0 as the MIDI event identifier somewhere
in its state, and everything is good to go. A basic loop for processing
input events in a plugin could look something like this:
Event_Port_Buffer* buf = ports[EVENT_PORT];
uint32_t index;
uint32_t next_frame;
uint32_t frames_done = 0
while (index < buf->used_size) {
next_frame = events[index].timestamp >> 16;
render_audio(frames_done, next_frame);
frames_done = next_frame;
handle_event(events[index]);
index += 1 + (events[index].size - 8) / 16;
}
render_audio(frames_done, nframes);
Should plugins have to list <http://lv2.example.com/uri-map> as a
required feature, or should that be implicit whenever a plugin has an
event port? Both methods have some drawbacks - if plugins are required
to list it there is some redundancy, if they are not we have a required
feature that isn't listed as one which can be a bit confusing.
I'm leaning towards listing it. It's just one triple in the data file,
not a huge deal. It's not out of the question that a more advanced (or
different, somehow) mechanism to do the same thing shows up at some
point in the future, though I don't see much of a reason why, can't
hurt to be explicit.
Does anyone else see any other problems with this type
of event port?
Steve, Dave, Nedko?
Other than the size thing I don't really get (8 bytes), I think it's
pretty good.
Once we figure out the basics I'll have a look at working my indexing
thing for OSC into it (allows constant time random access for any
event, at the cost of a bit more complexity writing the buffer, but this
will probably be done by common code in a header/library anyway).
Ignoring that for now though....
FWIW I'm a really, really big fan of a generic event mechanism like
this. One thing we might want is a way of saying "this port is /only/ a
MIDI port", mostly for UI issues. That's just a touch of RDF though.
Code side seems good.
-DR-