[linux-audio-dev] Re: Some Event stuff for now...

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: [linux-audio-dev] Re: Some Event stuff for now...
From: David Olofson (audiality_AT_swipnet.se)
Date: la syys   25 1999 - 13:46:40 EDT


[Seems like I forgot to reply to this...]

On Wed, 22 Sep 1999, Benno Senoner wrote:
[...]
> David,
> I'm still missing a clear picture of the event buffer.
> David, you say that you want to flush the buffer on each buffer period.
> Do you plan to use per-plugin event buffers ?

Yes, that was the idea. However, there's a distinction between the buffers of
event pointers that are sent to the plug-ins, and the buffers (or heaps) that
hold the events. The pointer buffers are allocated per plug-in, while memory
for events is allocated from a heap that's local to the processing sub net. (The
definition here is that a sub net has a uniform cycle time.)

There's one basic rule required for this to work: All events should have time
stamps within the cycle/buffer for which they are queued. That is, event
buffers are indeed very similar to audio buffers - only more structured in
their internal format. (You could actually view them as data buffers with
dynamic size, where the internal details are handled by the plug-ins.)

> Sorry if I dont understand this, but I often have to think in terms of pratical
> examples.

I don't blame you! :-) This is far from trivial, and I have yet to release a
detailed description of the whole system...

> Assume a simple sampler-plugin:
> input: MIDI NoteOn / NoteOff events (to specify triggering and pitch)
> output: sample-stream in float format
>
> assume that there are 2 sequencers bombarding the poor sampler-plugin
> with Note-on events.
> Of course you want to allow timestamped events, therefore the plugin has to
> schedule to events in right order.

Yes. And for performance reasons, only one event buffer for the plug-in to keep
track of. (Multiple input channels would result in extra conditional code in
the main paths of both plug-in and engine code.)

> When do you know to free the buffers ?

The buffers for the whole sub net the sampler is in can be flushed after the
full buffer cycle.

> You said "flushing on the next buffer period", but what if the timestamped
> event has to be scheduled several periods later.

You don't do that. The event system itself is not a sequencer. (It could be,
but that would complicate things a lot.)

> Do you need an additional buffer to queue up timestamped events ?

Well, kind of, just as you need to queue audio buffers to handle the
connections between sub nets with different cycle rates. So, if the sequencer
really has to run in a different sub net that is out-of-phase, or running at a
different cycle rate, the event timing code will have to take care of that,
just as it will take care of translating time stamps into local buffer frame
counts.

> Ok, you can advance the heap pointer for non-timestamped data, but
> for timed events you have to take an other buffer flushing mechanis.

...or, when you allocate memory for the event, make sure to pick a heap that
will not have been flushed before the event is to be processed. (That doesn't
mean that it has to be the destination sub net's heap...)

> But since David does have a diabolic mind, he has already solved this issue.
> :-)

Well, it's solved for the sub nets, but my mind is not as diabolic after a
tough week at work, so I have yet to sort out some of the inter sub net mess.

> > The reason for using arrays of pointers rather than just events as raw data
> > written sequentially into the output buffer is on the engine side - merging of
> > events from multiple sources etc...
>
> Ok, but these pointer have to point so some useful data, and you must
> alloc/free the data at some point, and this must be implemented using fast
> routines.

Yes. This is what the local sub net heaps with inline code is for. It's more
like a way for the whole sub net to share temporary storage, than a real memory
management subsystem.

> Again in the case of timestamped events you have to pay attention when
> to free the structs.
> Or is this problem already solved ?

As I said, it's solved inside sub nets, but it gets more complicated when
crossing sub net boundaries.

The easy hack is to do it by copying the events into the target heap when
translating time stamps (which is another inter sub net comm. only job - not
needed within sub nets), but that's not very efficient, and shouldn't be
necessary. I think some kind of circular buffers between sub nets could do the
job.

Other schemes may simplify this part, but does anyone have a suggestion that
does that without slowing down the average case? (The average case being
sending events between plug-ins in the same sub net, I believe.)

> > /*
> > * The engine encode time stamps as samples from
> > * start of the timing master buffer, which can be
> > * selected by the plug-in.
> > * (Alternatively, this could be a float, but I
> > * think that should be optional for performance
> > * reasons.)
>
> Yes, but what if the samplerate changes ?

Should sample rates be allowed to change in the middle of a buffer for normal
plug-ins? (And that's the *output* buffer sample rate.) That could be handled,
but I think it would be adding very much overhead to support a very unusal
situation. While other plug-in systems can't handle sample rate changes *at
all*, isn't it enough for us to allow it between the buffer cycles?

> > struct event_t;
> >
> > struct event_port_t {
> > int events; /* Number of events currently in the buffer */
> > int maxevents; /* Size of the buffer */
> > event_t **buffer;
> > };
>
>
> what is exactly an event_port ?
> A place where you can send events ?
> in the sample-player-plugin case:
> it the input-port of the plugin where you send the MIDI events ?

Yep. In the normal case (ie when plug-ins within the same sub net
communicate) it's little more than way to keep track of the event pointer
buffers. When sending events to someone in outside a sub net, it can actually
belong to an interface layer in the engine rather than to the plug-in you're
sending to, but that doesn't make any difference to you as a sender.

> > (event_t is of course just the header - any number of bytes of data may follow.)
> >
> > Any ideas about the from field? What I mean is, a simple way of making sure that
> > no one tries to reply to an event from a port that was just removed? (I think
> > it'll become clear when dealing with the life time of event buffers. When all
> > buffers with events from a certain port have been flushed, it's safe to delete
> > the port - unless some plug-in decides to remember a reply port address for
> > later use... That should probably not be allowed.)
>
> What about to require the event-senders to notify the event-receivers
> that they want to exit ?
> Maybe we could use double indirection:
> the **from is a pointer to a function pointer which gets the real from address.

That's about what I had in mind, although I'd just say
        event_port_t **from;
No function call. That is, when you register an event port to use as your "reply
address", you get a pointer to an entry in a static table. The table is an
array of event_port_t *, and all unused entries are set to a dummy event port
that just flushes it's heap (== clearing a variable or two in a struct) every
now and then. (You can also route it to a plug-in that yells "Coward!!!" when
someone sends a request event and then disappears without waiting for the reply.
:-)

[...]
> therefore in the case that the event-receiver wants to query data about the
> event-sender, there will be a function which will return PORT_NOT_PRESENT (=
> plugin exited or so),

Design goal: No function calls from plug-ins in the event system! :-)

//David

 ·A·U·D·I·A·L·I·T·Y· P r o f e s s i o n a l L i n u x A u d i o
- - ------------------------------------------------------------- - -
    ·Rock Solid David Olofson:
    ·Low Latency www.angelfire.com/or/audiality ·Audio Hacker
    ·Plug-Ins audiality_AT_swipnet.se ·Linux Advocate
    ·Open Source ·Singer/Composer


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : pe maalis 10 2000 - 07:27:12 EST