[linux-audio-dev] The Plugin API Fusion Proposal

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

Subject: [linux-audio-dev] The Plugin API Fusion Proposal
From: David Olofson (david_AT_gardena.net)
Date: ti maalis 07 2000 - 22:10:04 EST


Here's the document I mentioned earlier...

Note that this doesn't mention the initialization issue. Should this
be done the "function calls + structs" way, or should the event API
be used? Is a separate interface for initialization an acceptable
shortcut, or will it create a serious problem with the
inter-application stuff later on? I think the details of what kind
of information is to be exchanged has to be thought through carefully
before making a decision here.

Two overlapping APIs is probably a *very* bad idea. (It almost
always is, as it opens up zillions of ambiguous ways of doing
things.)

---8<------------------------------------------------------------

The Plugin API Fusion Proposal
------------------------------
The MuCoS Event System as a LADSPA port type

I just had a little idea... I'll try this ASAP, but I'd like to
share my thoughts (and sort some of the out) first. Hopefully, this
also explains some more of what's been going on in the Mad
Scientist's lab lately... ;-)

Basically, my current MuCoS design is pretty similar to the LADSPA
proposal except for the event system part. As a consequence of the
design idea that the event system should be the API, MuCoS keeps the
data streaming ports private to the plugin. It's up to the plugin to
keep track of those ports any way the developer wants. With LADSPA,
the host should fill in those pointers directly before the plugin is
called, as there is no event system to tell the plugin to do it at
the desired points during the execution of the plugin's run() call.

Now, by simply adding something like my MuCoS Event Port as an
alternative to the LADSPA signal and control port types, we get an
API that can be used just like simple and efficient LADSPA, while
allowing plugins to be easily extended to send and receive sample
accurate events, handle multiple asynchronous buffer splits within a
single call, send and receive out-of-band/soft real time data from
within hard real time engines and so on...

Basic kinds of plugins, using the same basic API framework:

Pure LADSPA (no events)
* The plugin has only signal and control ports
* The host drives the ports directly

Pure MuCoS
* The plugin may have signal ports and event ports
* A plugin may have only one single event input port
* The host may drive the signal ports directly, or via the
  event input port

Extended MuCoS (Like Pure MuCoS plugins, but...)
* A plugin may have multiple event input ports

The distinction between Pure and Extended MuCoS style plugins is
because of the added complexity of decoding events from multiple
sources. It should (probably) never be used by a normal, stream
centered plugin. However, in some cases, multiple input ports as a
valid plugin design can be very useful. As an example, it allows an
engine without built-in event routing to use a set of special
merge/split/remap etc plugins instead, to get full MuCoS support
without any actual routing code.

MuCoS and event routing
-----------------------
(Since I'm not going to be able to release interesting code for yet
a few more days, here's a brief explanation of the current routing
scheme.)

>From the plugin POV, there are input ports and output ports. You
normally have only one input port, which controls an outer loop
outside what would be the normal process code of a Pure LADSPA
plugin. (That loop checks the timestamp on the next event, runs the
inner loop until it reaches that time, and then processes that
message. This is repeated until a run() call terminator event is
found, which causes tho plugin to write back any temporary signal
pointers and return to the host.)

Input ports
-----------
An input port has a number of Target Channels, which are presented
to the host much like the LADSPA ports. When sending an event to an
input port, the Target Channel is specified as an integer number
inside the event. (*) Here comes...

(*) I'm still hesitating as to whether there it is a performance win
to avoid copying events for multiple recipients, or if the general
case overhead involved with an extra level of indirection eats that
win. How big is the average event in the kind of systems we'll be
developing? Note that they're *not* supposed to get any bigger than
say, 128 or 256 bytes - bigger than that, and the data should be
passed by reference ("huge block/out-of-band events").

Problem
-------
My intention with MuCoS was that an event port Target Channel on the
*single* event input of the plugin port should map 1:1 to the
streaming channels. That is, if a plugin uses channels 0..3 for audio
input, the host should send New Buffer Pointer events and other
directly audio channel related events on those channels. The plugin
can then decode the channel numbers by just indexing into it's
internal streaming port arrays.

Should this simply be copied to the Fusion version? That is, mapping
MuCoS event channels to LADSPA ports? The problem with that is that a
MuCoS event input port might have practically *any* number of input
channels (well, at least 65k as of now). OTOH, the non audio channels
may have no useful mapping to LADSPA ports. Some *could* map to
LADSPA control channels, though...

Next, what about Extended MuCoS (multiple event input ports)
plugins? Should all input ports use the same mapping? Is there a need
for the host to actually understand that all inputs belong to the
same plugin? (It has to, unless the plugin cannot provide different
Target Channel descriptions for the ports, in order to avoid setting
up more than one port that maps to the signal port(s).)

Output ports
------------
A MuCoS event output port is actually just a description of what
that port is used for, and some info for the host regarding the low
level details, like data types and events it may send. The address
of the physical port to send events to (a host may connect multiple
output channels to the same physical port) The target channel the
host wants the plugin to put on events sent from this output channel
(This goes into the channel field of the events, as described above;
"Input Ports".)

That is, an output port basically has two-dimensional addressing;
Physical Port and Target Channel. That way, the host can do most of
the routing when building the processing net, rather than at run
time, touching individual events. The plugins sending events have to
fill the events in anyway, so that's where it's the least extra
overhead doing it. (Oh, that's what I think before actually having
coded some plugins that way... ;-)

(Note for hackers: The allocation and sending of events is to be
done by macros for ease of use and less lines of code. These macros
could come in versions that fill in the Target Channel field and
picks the right output port automatically.)

Subchannels
-----------
Just an idea I had when thinking this port/channel scheme up the
other week. Instead of specifying in the API that there be 32 bit int
Target Channel fields in events, why not split them into two 16 bit
fields? (65k Target Channels with 65k subchannels each should do for
most plugins, right...? :-) The subchannels shouldn't normaly be
considered for event routing, but more like an extension of the event
kind code. Plugins may use subchannels for related things, getting a
chance ta do quick, index-into-array style decoding, rather than
adding new event kinds to the API.

(As of now, I think there should only be very few but generally
useful events, so that we get less of "I need this event! And this!
And that would be cool too...", and more "Hey, that's a float output
channel! Which means I can connect to this input one way or another.")

Virtual channels
----------------
Another idea that can eliminate copying of events in most cases.
Virtual channels add an extra layer of abstraction between output
channels and target channels, allowing the host to map the same
Virtual Channel (the field of an Event) to different actual Target
Channels on different plugins.

On the output port side, it means nothing more than the Target
Channel the host specifies for an output channel not mapping directly
to a Target Channel of the plugin that will receive the events. That
is, when sending events, what you put in the Target Channel field of
an Event is actually a Virtual Channel index.

It does mean that the input port gets a translation table. The table
is managed by the host, and is used by the input port to look up the
actual Target Channel (as specified by the plugin) for the Virtual
Channel specified in each Event received. This allows the host to
build one Virtual Channel to Target Channel mapping table for each
plugin, so that it can reuse events rather than copying them, just to
change the Target Channel field.

Hope this makes some sense for once... :-)

//David

.- M u C o S --------------------------------. .- David Olofson ------.
| A Free/Open Multimedia | | Audio Hacker |
| Plugin and Integration Standard | | Linux Advocate |
`------------> http://www.linuxdj.com/mucos -' | Open Source Advocate |
.- A u d i a l i t y ------------------------. | Singer |
| Rock Solid Low Latency Signal Processing | | Songwriter |
`---> http://www.angelfire.com/or/audiality -' `-> david_AT_linuxdj.com -'


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:23:28 EST