On 05/09/2013 10:46 PM, David Robillard wrote:
(Sorry for the late reply, I don't monitor LAD
very closely these days)
You should be able to handle all the events in one loop.
However here you seem to be iterating over all events *for every frame*?
That would cause a problem with loading since you'll issue a ton of
identical load requests, but it also probably isn't what you want for
MIDI either. You'll trigger everything repeatedly and the timing is
wrong. I think you need to unify your two loops here.
Nope, I do not iterate over all events in every frame. Before iterating
over the frames I get the first event and then on every frame I iterate
over those events that have that frame time.. This is similar to how the
jack_midi example code does it..
// First the worker events stuff ONCE per run() call
LV2_ATOM_SEQUENCE_FOREACH(self->control_port, ev)
{
[...]
}
// Then the iteration over the frames...
LV2_Atom_Event *ev =
lv2_atom_sequence_begin(&(self->control_port)->body); [...]
for (unsigned frame_index = 0; frame_index < sample_count; ++frame_index)
{
[...]
while (false == lv2_atom_sequence_is_end(&(self->control_port)->body,
self->control_port->atom.size, ev) && ev->time.frames == frame_index)
{
[...]
ev = lv2_atom_sequence_next(ev);
} [...]
// Did we reach the end of a chunk or the last of the sample_count?
if (0 == (frame_index + 1) % buffer_size || sample_count == frame_index + 1)
{
process(self, frame_index % buffer_size + 1, chunk_index * buffer_size);
++chunk_index;
}
}
The general pattern for sample-accurate event
receiving is work through
time in the event loop, outputting everything up to the current event.
So you start with t=0. The next event loop in the loop is at t=5, so
render the output for 0..5, process the event (to e.g. trigger a voice
or whatever), then continue. After the loop output everything from the
last event to the end of the cycle.
So your event processing loop is your processing loop, and proceeds in
'chunks' delimited by events.
The magic of the worker extension is you can do non-RT things like load
new sample banks, which will happen RT-safe (with latency) if running
realtime, but if freewheeling (e.g. for export) the scheduled work will
execute immediately/synchronously. Thus you can get sample accurate
exporting, e.g. with a patch load at t=0 and a note on at t=1 the note
is guaranteed to play with the new patch (in the export). You don't
need to worry about this, but it's why things are the way they are...
plus it's pretty cool :)
Hopefully that makes sense, the simplest example of how to do this is in
the metro example:
http://lv2plug.in/browser/trunk/plugins/eg03-metro.lv2/metro.c#L296
I do use the worker extension. The only problem I saw was when I tried
to integrate the patch_set messages in that same loop.
Flo
--
Florian Paul Schmidt
http://fps.io