[linux-audio-dev] Plugin APIs (again)

David Olofson david at olofson.net
Mon Dec 9 23:03:01 UTC 2002


On Tuesday 10 December 2002 02.15, Tim Hockin wrote:
> > 	struct XAP_bay_descriptor
> > 	{
> > 		const char		*name;
> > 		XAP_channel_type	channel_type;
> > 		int			min_channels;
> > 		int			max_channels;
> > 		/*
> > 		 * Maybe some other stuff
> > 		 */
> > 	};
> >
> > If you like, you may have several Bays with Audio Input Channels,
> > for example. These would be totally independent WRT min/max
> > channel counts, audio format or whatever properties Audio
> > Channels may have.
>
> So let me see if I get the the containership correct:
>
> a Plugin has n Bays
> a Bay has m Channels

Correct.


> a Channel has p Controls and q Ports

Well, a Channel can have p Controls OR p Audio Ports. I would say 
that a Channel can vave p *Slots* - where a slot can be one of:
	Audio Input Slot
	Audio Output Slot
	Control Input
	Control Output

Event Ports don't really belong in this picture. They're like a 
flexible resource that the Plugin may use pretty much as it desires.
They are owned by the Plugin instance, and their relation to Bays, 
Channels, Controls, phase of the moon or whatever, is controlled 
entirely by the Plugin.

When asked to connect a Control Input, a Plugin will hand you the 
address of a suitable Event Port, as well as a 32 bit Control ID that 
the Plugin may encode in any way it feels like. (As described in an 
earlier post.)

This is how you can chose between single Port/one Port per 
Channel/one Port for every N Channels/one Port per Control or 
whatever you might find useful, efficient or just generally cool.


> I know at some point you started thinking of event ports as
> separate channels.

Actually, one event port per channel. Then I realized you don't have 
to specify this in the API at all!


>  I am almost convinced that different channel
> kinds are needed, but Bays has thrown me.

Bays are actually a way of grouping channels of the same kind 
together. I initially called them "Channel Kinds", until I realized 
that I had already "invented" the term "Bay" for exactly this thing 
for MAIA.


>  This is what I was
> thinking about as I slept (weird dreams...)

You have those too? :-)


> Plugin {
> 	/* everything has master controls */
> 	n_master_controls;
> 	master_controls[];

Yeah, since there will probably be a few "system" events that plugins 
*must* implement anyway... Or maybe not. No big deal. We'll see.


> 	n_master_eventports;
> 	master_eventports[];

These won't be public. (See above.)


> 	/* many plugins will have 1 template, but they can have more.
> 	 * multi-timbral instruments (synth part, drum part, ...) and
> mixer * slots (mono, stereo, ...) come to mind
> 	 */
> 	n_channel_templates;
> 	channel_templates;

This sounds pretty much like my Bays. You have one template for each 
"kind" of channel you want, and then you can have varying numbers of 
channels of each kind?


> 	/* mixers might start with 0, synths might start with any #,
> simple * instruments might start with 1.
> 	 */
> 	n_channels;
> 	n_channels_min;
> 	n_channels_max;
> 	channels[n_channels_min];
> }

Still a 1D array of channels, that is?

I'm thinking about Bays as an array of objects that each has an array 
of Channels - but it doesn't have to be that way physically, 
obviously. I just think it seems easier with arrays of arrays (2D) 
since Bays have independent Channel counts, that might even change 
during the lifetime of the plugin. (That's another issue we have to 
deal with...)


> Eventport {
> 	label;
> 	name;
> 	/* anything else? */
> }

Mine look like this:

typedef struct AEV_port
{
	/*
	 * Note that when 'first' is NULL, 'last' is undefined!
	 * (If there's no first event, there can't be a last
	 * event either - makes sense, eh? :-)
	 */
	AEV_event	*first;
	AEV_event	*last;
	const char	*name;
} AEV_port;

But again, note that this is a very low level thing, that plugin and 
host code well nearly always treat as an opaque data type. It's part 
of the API, but ports don't have public names or anything. (My name 
field is only for debugging, so you can look at a port and see where 
it belongs.)


> ChannelTemplate {
> 	label;
> 	name;
>
> 	/* could be split to per-channel and per-voice */
> 	n_controls;
> 	controls[];

Well, it just happens that channel + voice control is a very 
practical model for most synths. It's probably not perfect and 
without restrictions, but I think we can do a lot of cool stuff 
before seeing much of these issues.

Anyway, I can see two ways of handling this:

	1. Have two control ranges for Event Input Channels.

	2. Allow only one range of controls per Event Input Channel,
	   and instead, use an extra bay of Voice Control Channels, if
	   you want Voice controls. One could mark the Bays with hints
	   suggesting that they are closely related.

Now that the strict physical relation between channels and Event 
Ports is eliminated, this doesn't matter at all performance wise, but 
it might make the API a bit cleaner.


> 	n_eventports;
> 	eventports[];
>
> 	n_inports;
> 	n_outports;
> }

I'd rather think of Bays as being in/out neutral, and use different 
Channel types for input and output. Only one array of Bays needed 
that way.


[...]
> > Number of Bays hardcoded or not?
>
> Assuming that we're using different words to get the same idea, no.
>  A Mixer would start with 0 Channels and (for example) 4
> ChannelTemplates (MONO_STRIP, STEREO_STRIP, MONO_BUS, STEREO_BUS) .
>  The host would somehow direct the plugin to add a new MONO_STRIP
> for each incoming connection and a STEREO_BUS for output.  Just as
> ideas..

Yeah, that sounds like what I have in mind. It's just that it creates 
some nasty issues for RT engines...


> You can now have different controls, different numbers of audio
> in/outs, and different event ports per Template.  And you can
> instantiate as many instances of each template as needed via
> plug->new_channel(template_num).

I see. Bays would be different from Templates in that each Bay can 
have only *one* kind of objects in it. It means that relationships 
between for instance control inputs and audio outputs cannot be 
expressed by grouping them together - but I think we have concluded 
earlier that this is not very useful anyway.

Linking Bays WRT Channel count may be useful, though... (If you have 
a mixer, you'd probably want exactly one strip automation control 
input for each stip audio input. :-)


BTW, this multichannel "group" issue... That "granularity" (or 
"group_size" or whatever) field would be in the Bay, and would still 
effectively say "for one imaginary channel, you actually need N real 
channels". This would make that Bay linking a whole lot more useful, 
since it would allow M Channels on one Bay to correspond to N 
Channels on another.

[...]

//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -'
.- M A I A -------------------------------------------------.
|    The Multimedia Application Integration Architecture    |
`----------------------------> http://www.linuxdj.com/maia -'
   --- http://olofson.net --- http://www.reologica.se ---



More information about the Linux-audio-dev mailing list