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

Tim Hockin thockin at hockin.org
Sun Dec 8 00:06:02 UTC 2002


> I think we're actually talking about *three* kinds of controls, while 
> everyone is still talking about their own set of two kinds of 
> controls. What I'm thinking is:

> 	Master Controls:
> 	Channel/Part Controls:
> 	Voice/Note Controls

So if we support multi-timbral (multi-part, multi-channel - too many words)
instruments, then  yes, this is true.

Aside: I propose the following for naming stuff:

* Plugin: a chunk of code, loaded or not, that implements this API (a .so file
  or a running instance).
* Instrument: an instance of a plugin that supports the instrument API bits
  (analogous to a chunk of hardware from Roland).
* Channel: a 'part', 'channel' or 'instrument' from MIDI.  Instruments have
  1 or more Channels.
* Control: a knob, button, slider, or virtual control withing a Channel or
  Instrument.  Controls can be master (e.g. master volume), per-Channel (e.g.
  channel pressure) or per-Voice (e.g. aftertouch).
* Preset: a stored or loaded set of values for all Controls in a Channel
* Voice: a playing sound within a Channel.  Channels may have multiple voices.
* Port: an input/output connection on a Plugin.  Audio data goes over ports.

> I don't think this has much to do with the API - and I don't see the 
> possibility of a clash. If you take any two controls, they may have 
> any relation whatsoever, *defined by the synth*, and the host should 

I agree with that IF we say you have to have a separate control struct for
per-voice and per-part controls.  If we define a control and say it has a
flag which identifies it as MASTER, PART, VOICE, then we do need to suggest
a relationship.  I like defining a control once, but it's becoming more
obvious to NOT do that.  They range of valid values may be wildly different.

Do we want to provide a suggested range of values for MIDI compatible
controls.  For example Controls that are labelled CONTROL_AFTERTOUCH should
expect values between 0 and 1.0, and the host can map MIDI onto that?  Or 0
and 127, like MIDI?  or 0 and MAX_INT and let the synth blow up when you
pass a VELOCITY of 10000, and it expects 127?

> You're thinking entirely in keyboardist terms here. :-) You're 
> forgetting that some instruments really don't have anything like 
> attack and release in real life, but rather "bow speed", "air speed" 
> and that kind of stuff.

umm, speed == velocity, no?  But I get your point, and I concede this point.
Velocity is an event.

> I think so, but I'm not 100% determined. (Audiality is still mostly a 
> monolith, and I'm not completely sure how to best split it up into 
> real plugins.)

> plugins from being multipart doesn't make much sense. Just reserve 
> one control/event port for the whole instrument/plugin, and then 
> allow the instrument/plugin to have as many other control/event ports 
> as it likes - just like audio in and out ports.

I had been assuming a single event-queue per instance.  Two questions:  why
would a plugin (assuming not multi-timbral for now) have more than one
event-queue?  Assuming we do support multi-timbral synths, is there an
advantage to having events per-channel event-queues?  Do you envision each
Channel getting the ->run() method seperately, or does ->run() loop?  If it
is looping anyway, is there an advantage to multiple event-queues?

> > > ports. As of now, there is one event port for each Channel, and
> > > one event port for each physical Voice. "Virtual Voices" (ie
> > > Voices as

I know you've done some exploring - do we really want one event-queue per
voice + one for each channel + one for master?  or is one per instance
simpler?

> > > As to the "gets a voice ID" thing, no, I think this is a bad
> > > idea. The host should *pick* a voice ID from a previously
> > > allocated pool of Virtual Voice IDs. That way, you eliminate the
> > > host-plugin or plugin-plugin (this is where it starts getting
> > > interesting) roundtrip, which means you can, amond other things:
> >
> > I'm still not clear on this.  What plugin would trigger another
> > plugin?
> 
> Any plugin that processes events rather than (or in addition to) 
> audio. They're usually called "MIDI plugins".

I can see controller plugins (It's another extension to this API, perhaps)
which deal with sending events to other plugins.  And I guess an arppegiator
plugin could be a controller..

> > If so, how do you reconcile that they
> > will each have a pool of VVIDs - I suppose they can get VVIDs from
> > the host, but we're adding a fair bit of complexity now.
> 
> Where? They have to get the VVIDs from somewhere anyway. It's 
> probably not a great idea to just assume that plugins can accept any 
> integer number as a valid VVID, since that complicates/slows down 
> voice lookup.

you don't send just ANY integer, you get the integer to id a voice FROM the
plug.  But if VOICE_ON is an event, it gets much uglier.  Do let me see if I
get this right:

Host allocates the VVID pool (perhaps a bitmask or some other way of
indicating usage)
Host wants to send a VOICE_ON:
	allocates an unused VVID
	sends VOICE_ON with that VVID
	when it sends a VOICE_OFF or receives a VOICE_OFF it can mark that
	   VVID as unused again.
Plugin wants to send a VOICE_ON:
	calls host->get_vvids(32)
	host allocates it 32 VVIDs
	sends VOICE_ON with any of those, and must manage them itself
	(alternatively, management is simpler if it just allocates one VVID
	at a time and frees it when it is done)

Or does the HOST ask the INSTRUMENT for VVIDs?  If so, why?  Explain? :)

> I'd much rather require that events sent to a port are sent in 
> timestamp order, so the host can just merge sorted event lists. In 
> cases where you have multiple connections to the same event port, you 
> just use "shadow ports", so the host gets a number of ordered event 
> lists that it merges into one just before running the plugin that 
> owns the real input port.

I agree - this is the host's job, not the plugin's

> > host has to handle syncronization issues (one recv event-queue per
> > thread, or it has to be plugin -> host callback, or something), but
> > that's OK.
> 
> Well, if your threads are not in sample sync, you're in trouble... 

I meant threading sync issues.  Host can't just pass one event-queue to all
plugins in a multi-thread environment.  But again, that is the HOSTs
problem.  So the host can pass the address of it's event-queue during
activate(), or the plugin can make a host->send_event() callback.



More information about the Linux-audio-dev mailing list