[linux-audio-dev] XAP and Event Outputs

David Olofson david at olofson.net
Mon Dec 9 05:45:01 UTC 2002


I did some thinking last night, and I have an interesting problem, as 
well as a nice solution - or so I think. Please tell me what you 
think.


Consider the following situation:

	* You have a plugin "A", which has 1:4:7 (Bay:Channel:Control)
	  (which is an Event Output) connected to some Event Input Port
	  named "P".

	* Now, you want to connect output 1:2:9 (Bay:Channel:Control)
	  to that same Event Input Port "P".

So, what's the problem?


Well, as I've mentioned before, having separate Event Input ports for 
Channels is probably an advantage in many most cases, since it avoids 
queue splitting overhead, and reduces event size. (No need for a 
"channel" field.)

Regardless of the above, any reasonably complex synth will most 
probably have several "inner loops" working through the same number 
of sample frames.

These two internal plugin designs have the same problem; you're not 
running *the whole plugin* one sample at a time, through the whole 
buffer. Instead, you're iterating through the buffer several times.

Now, the *problem* is that whenever you send an event from inside one 
of these event and/or audio processing loops mentioned above, you 
risk sending events out of order, whenever two loops send to the same 
port! (Note that you can't know that without comparing a ton ofp 
ointers every time a connection is made. The host just tells you to 
connect some output, and gives you an Event Port pointer and a target 
Control Index to send to.)

In theory, the problem is very easy to solve: Have the host throw in 
"shadow event ports", and then have it sort/merge the queues from 
those into a single, ordered queue that is passed to the actual 
target port.

However, how on earth could the host know which outputs of a plugin 
can safely be connected to the same physical port, and which ones 
*cannot*?


Easy: Output Context IDs. :-)


Whenever the host wants to connect an output, it asks 
plugin->get_context_id(bay, channel, output), and gets an int. The 
actual values returned are irrelevant; they're only there so the host 
can compare them.

How to use (plugin1 and plugin2 being the two plugins that have 
outputs to be connected to the same physical event port):

struct XAP_cnx_descriptor
{
	XAP_plugin	*plugin;
	int		bay;
	int		channel;
	int		output;
};

/*
 * When you're about to make a connection to an input event port
 * that already has connections, use this to figure out whether
 * or not you need to do shadow + sort/merge.
 */
int must_shadow(XAP_cnx_descriptor *from1, XAP_cnx_descriptor *from2)
{
	int ctxid1, ctxid2;
	if(from1->plugin != from2->plugin)
		return 1;	/* Yes, *definitely* --> */

	if(!from1->plugin->get_context_id)
		return 0;	/* No, this plugin has only
				 * one sending context. -->
				 */

	ctxid1 = from1->plugin->get_context_id(from1);
	ctxid2 = from2->plugin->get_context_id(from2);
	return (ctxid1 != ctxid2);	/* Only if ctx IDs differ. */
}


//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