[linux-audio-dev] XAP status : incomplete draft

Tim Hockin thockin at hockin.org
Fri Dec 13 14:30:01 UTC 2002


> > #include <stdint.h>
> 
> I'm thinking about using that as well - but how portable is it these 
> days? (No big deal, though. Just get one, or hack a fake if you 
> platform shouldn't support it for some strange reason.)

C99 is here, use it :)

> > /*
> >  * The current version of the API: read as "major.minor.micro".
> >  */
> > #define XAP_VERSION			0x000010
> > #define XAP_MKVERSION(maj, min, mic)	(((mar)<<16) | ((min)<<8) |
> > (mic))
> 
> I generally prefer 8:8:16 format these days, so the minor version 
> field can be used as something like the serial field below. (Why have 
> both?)

This is the current XAP API version.  Serial is the plugin version.

> > struct XAP_descriptor {
> [...]
> > 	uint32_t xap_id;
> 
> Why the xap_ prefix on all the fields in the struct?

Old habit - prefixing struct fields with soemthing to identify the struct.
Makes it trivial to search for all uses of ->xap_label as opposed to ->label
(which exists in several structs).  If people REALLY hate it, I can let it
go.  I try to always do that in exported code.

> I think this belongs in version, as the micro field. Hosts should 

Version is a string - it could be "1.0" or "1.0 rc26" or "foobar".  Host can
not interpret a string.  Serial is for multiple builds of the same plugin.
It makes life easier - think of it as a build number for binaries, maybe?

> > 	const char *xap_label;
> 
> Why is this needed? (There are unique IDs, I mean...)

LADSPA compat, and it is handy.  'name' may change.  It may be localized.
'label' is never localized.

> > 	const char *xap_version;
> 
> This sort of doubles the 32 bit version field, so I'm not sure 

See above - is it stil unclear?

> > 	/* master controls and I/O */
> > 	int xap_n_controls;
> > 	XAP_control **xap_controls;
> 
> Maybe... I was thinking that you might as well require that the first 
> Control Port supports "maximum buffer size" (very important!) and 
> that kind of stuff - but where's the "first" Control Port!? If you 

Which is why I threw in master controls - I don't want to have channel 0
always be master.  The channel numberspace is reserved for channels.

> > 	int xap_n_ports;
> > 	XAP_port **ch_ports;
> 
> What are these for? Shortcut to avoid the more complex system below, 
> when you don't really need it?

Audio ports - master audio ports.

> > 	//FIXME: how to get the num/info currently instantiated channels?
> 
> When and why? I mean, isn't the host supposed to remember what it's 
> done?

That is fair.  I can live with that answer

> [...]
> > 	void *(*xap_create)(XAP_descriptor *descriptor, XAP_host *host,
> > 	    int rate);
> 
> Why only "rate" here - or rather, why "rate" at all? I think there 
> are more things that a Plugin might want to know, so it might be 
> better to pass this kind of info some other way.

As discussed before - setting the rate is something you ought not do often. 

> > 	//FIXME: how to enumerate errors from this?
> > 	//FIXME: return something better than void *?
> 
> If you use the state() thing, you have a *very* simple initialization 

I gave thought to the state model, and while it seems nice, there are only
two states that are really needed: INACTIVE and ACTIVE.  Before you are
instantiated, you have no state.  After you are instantiated you are
INACTIVE.  activate() makes you ACTIVE.  deactivate() makes you INACTIVE.
Are there really other states that are meaningful?

> > 	 * set_rate: set the sample rate
> > 	 * This method may only be called on plugins that are not active.
> (Same thing as controls that may only be changed in certain states.)

ALL plugins must support set_rate.  The way I see it, controls are optional.
There is no control that every plugin HAS to define.  OPtional things are
controls.  It is a nice way of indicating I do/don't support 'feature'.
Non-optional stuff ought not be controls, IMHO.

> > 	int (*xap_activate)(void *plugin, int quality);
> > 	int (*xap_deactivate)(void *plugin);
> 
> This is both hairy and incomplete, IMHO. One state() call or 

What's missing?  I thought about state() and decided this was complete.  Did
I miss something?

> have hosts calling these functions in the wrong order, and the order 

Which is why I want two states.  It's easy to get right :)

> > 	XAP_event_port *(*xap_event_port)(void *plugin, int channel, int
> > index);
> 
> I don't think it's a good idea to require that the plugin returns a 
> struct. This would mean that the plugin needs to allocate memory for 

ok, I'll pass a pointer to a struct to fill.  I like that better, actually.

> I think "now" should be in the host interface struct. Any plugin that 
> deals with events will have to mess with the host struct, and either 
> way, "now" changes only once per block and host; never for each 
> plugin. (It cannot, because plugins would be out of sync with the 
> host WRT timestamp conversion requests and the like...)

What about buffer splitting?  You then force the host to have separate host
structs for plugins?

> > struct XAP_host {
> > 	//FIXME: some sort of host ID/version ?
> > 	uint32_t host_api;
> Yes!

just to clarify - host_api is the XAP_VERSION the host understands.  Do you
think we also need a per-host identifier?  Is a string good enough? (I don't
want to have to manage host IDs and plugin IDs :)

> > 	//FIXME: how does the host know where an event came from?
> > 	XAP_event_queue *host_queue;
> 
> It basically doesn't - but it does (hopefully) know which plugin it 

What if we have a host->get_event_port(..., XAP_event_port *evport);
The host can then pass the event port it wants to the plugin with a cookie
that it can use to ID a plugin (the plugin address or something else it
wants).  It's elegant - it works the same both ways.

> > 	void (*host_alloc_failure)(void);
> 
> Why? You can just return a suitable error code...

What if the host has some fallback actions? 
* Plugin calls some form of allocation NOT through the host
* allocation fails
* plugin call host->alloc_failed()
* host can abort(), or free stuff, or sleep for a while, or whatever is
appropriate.
* host returns a code to plugin: 'try again' or 'give up'.

It gives the host write a chance to trap a memory allocation failure and do
something useful but consistent with it (print __FILE__:__LINE__ or whatever
it does).

> > #define XAP_RTFL_MALLOC		0x02	/* allocates/frees memory */
> > #define XAP_RTFL_HMALLOC	0x04	/* allocates memory through the host
> > */
> 
> This should not be optional for normal plugins, IMHO. The host struct 
> *is* your source of resources - you may not use OS resources directly.

Well, some plugins will want to use library routines that use allocators
other than host->malloc.  If a control does this, it should flag itself as
RTFL_MALLOC.  HMALLOC can be noticed by smart hosts and if they support an
RT-safe host->malloc, ignored.

> Speaking of driver plugins, those will also have to tell the host 

driver plugins?

> > #define XAP_RTFL_HFREE		0x08	/* frees memory through the host */

ok, I'll unify with RTFL_HMALLOC

> > #define XAP_RTFL_SLOW		0x20	/* is 'slow' in general */
> 
> Well, everything is relative...
> 
> I think it would be much more interesting to have a warning hint for 
> plugins that are significantly nondeterministic in their CPU usage. 

That's really what SLOW meant - it may run in non-deterministic time.  but
SLOW is shorter than RTFL_NONDETERMINISTIC :)  Suggest alternative name?

> > #define XAP_CTRLHINT_AFTERTOUCH		"AFTERTOUCH"	//voice
> > #define XAP_CTRLHINT_CHPRESSURE		"CHPRESSURE"	//channel
> 
> We should not separate these. They're exactly the same thing, only 
> one is a channel control and the other is a voice control. (Which 
> indeed *are* incompatible due to differing addressing needs, but 
> that's a different story.)

ok, will unify hint

> > #define XAP_CTRLHINT_PITCH		"PITCH"		//channel,voice
> 
> ...and the optional "NOTE_PITCH" that no one will ever use, of 
> course. ;-)

I've completey ignored the pitch thread until I had time to digest it :)

> 
> [...]
> > #define XAP_CTRLHINT_HOLDPEDAL		"HOLDPEDAL"	//channel,voice: bool

> Why boolean? (That's more annoying than helpful with MIDI, IMHO... 
> Real instruments rarely have *truly* boolean pedals and stuff, and 
> sometimes, you actually want to make use of that. Whether synths 
> check for anything but "value > 0.5" is another matter.)

ok - changed





More information about the Linux-audio-dev mailing list