Re: [linux-audio-dev] big picture, for a moment

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

Subject: Re: [linux-audio-dev] big picture, for a moment
From: Paul Barton-Davis (pbd_AT_Op.Net)
Date: ti loka   12 1999 - 12:18:13 EDT


Getting closer ...

>...while I view a plug-in as a black box with a number of inputs and
>outputs, in the form of audio ports and event ports. The average
>plug-in would have >=0 audio inputs, >=0 audio outputs, one event
>input, and possibly one event output. During initialization, the
>plug-in will tell the host what events it understands (little more
>than info for the UI), and if it has an output port; what events it
>might send through it.
                        
=======================================================================
> The plug-in doesn't care (or know) who listens
>to it's output, nor does it know where the events it recieves come
>from.
=======================================================================

we both absolutely agree on this key point.

i think that our difference is small here. i look at the address of a
port as being a statement about the events the port will "send". if
you make this concession for a moment, i think you'll find we're
saying something very similar. the plugin tells the engine what it
understands. you say that it says "i understand float #5", whereas in
my view, its says "i understand midi cc 34". the only difference here
is what the semantics of an address are, for perhaps float 5 *is* midi
cc 34 ! in both cases, the engine will subscribe the plugin to a
particular port, right ?

more precisely, i think that event ports should be able to declare
themselves more strongly typed than you are thinking. a plugin's
output port might not be very strongly typed, but the MIDI sensor
thread, for example, might declare many different ports each of which
would *only* ever contain events connected to the ports
"name/address".

why does this matter ? imagine a plugin that is a MIDI data
viewer. it says "i understand raw MIDI data". another plugin says "i
understand float #5". another says "i understand MIDI CC 34".

you do *not* want to hook all these plugins up to a single port from
the MIDI sensor thread. instead, the first plugin gets connected to
the rawMIDI port, the second to some time-dependent port that happens
to be synonymous with "float #5" for now, and the third to a port that
contains messages about changes to MIDI CC 34.

this will cut down a lot on the amount of iterating over meaningless
events that plugins have to do.

essentially, i want *more* flexibility than you in that i want event
sources to be able to *restrict* the engine's view of the kinds of
events that will be posted to their port(s).

most plugins might only declare a single port, but others might
declare many ports. consider a plugin that provided a GUI for a mixing
console (its on my mind:). instead of mux-ing all the events for
parameters for every strip into a single port, it would declare N
ports, one for each strip. Then the plugins that were implementing
strip-level FX/EQ would just be subscribed to that port, not a port
that would contain a bunch of events they didn't care about at all.

in essence, i imagine a heterarchy of ports, some completely generic,
some totally specific: "this port posts byte events describing the
state of the I-Cube tap sensor".

any "input port" (really, just a pointer to a port, since there is no
data copying) that could handle byte data could be connected to this
port, but in addition, a plugin that listed a set of possible sources
for its displays could show "I-Cube tap sensor", and connect directly
to that port.

and imagine being able to dynamically describe all the ports in the
system:

        Port Description Data Type Source
        --------------------------------------------------------
        #13 generic float pluginNN
        I-Cube tap sensor byte pluginNM
        #14 generic string pluginXX
        #15 pluginNN_t struct pluginNN
        #16 audio audio sensor4
        MIDI CC 34 byte sensor5

and so on. I regard this as equally generic as your system, but also
potentially much more efficient. What do you think ?

A last comment on this. None of the above is supposed to change the
basic notion that event sources have no idea who is listening, and
event receivers have no idea of the event source. From a plugin's
perspective all that matters is the *address* of a port, which also
tells us something about its usefulness to the plugin. The plugin, in
subscribing to port XXXXX has no idea where events on that port come
from.

>Well, compare that to the overhead involved when handling the number
>of event ports needed to get the same flexibility.
>
>Input from multiple senders:
>
> * The engine has to merge the events into one list,
> and they must be sorted according to the timestamps.

yes, but what is the problem with that ?

the plugin process() call looks like:

     /* build a Lisp-like sorted list of all events on each
        subscribed port that occured before the current deadline.

        *NOTE* NO DATA COPYING: the list is just a set of pointers
               to the event_t's still in the ports event lists.
      */

     mcs_build_event_list (&plugin->ev_list, &plugin->ports);
     plugin->process (..., event_list_t *events, ...)

>Output to multiple destinations:
>
> * _ALL_ events will have to be copied to _ALL_
> destinaiton ports by the engine, as the sending
> plug-in has no idea who's listening to what. And
> neither does the engine...

no. events are never copied at all. they exist on a port's event
list. things that listen to the port will find them there.

>Now, lets find the flaws in my version! :-)

since mine is simpler, mine first :)

>This is true for point-to-point connections, while subscribing to
>multiple event sources put you in a network...

not if you accept that plugins receive events from multiple ports.

>Very handy... However, I wonder if it's really a win, performance
>wise. How much does it cost the engine to put that end-of-cycle
>marker in, compared to the plug-in checking the timestamps?

right, its not necessary, now that we have timestamping worked out.

>What I'm thinking about is that it's not necessarily true that there
>are no events after the last one to be processed during the current
>cycle. There may be events to be processed later on... This happens
>when interfacing between sub nets with different buffer sizes, and
>when communicating accross threads.

leaving aside the subnets with different buffer sizes, i thought that
the whole point of the design here was something like this:

events arrive during one pass through the plugins' process()
functions. they are timestamped with the sample on which they
occured. during the next pass through the plugins, the plugins get to
process the events, because the sample timestamps will correspond to
samples they will generate/process during that or a later call to
process().

>As long as the GUI is also in its own *file*, OK. I can load ELF into
>kernel space and similar weird places, but I don't feel like cleaning
>out "irrelevant" code on the fly...

sounds fine.

>Why? That's *exactly* where the intermediate FIFO hidden behind the
>shadow ports come in handy. If sensor threads can do it, so can
>clients, *and*, it makes them a lot more similar to plug-ins. A
>client is to MCS what a plug-in is to an engine... To some extent at
>least; clients can do lots of cool stuff that plug-ins cannot.

fine. its more complex, and it will involve more overhead on both
sides of the communication link, but fine. i don't buy any of this
shadow port stuff - i think its a totally unnecessary concept. i think
that ports should just be event FIFO's: posted to by event sources,
read from by port subscribers, and cleaned out by the engine.

--p


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:59 EST