[linux-audio-dev] more on XAP Virtual Voice ID system

Tim Hockin thockin at hockin.org
Wed Jan 8 03:17:01 UTC 2003


> > The plugin sees a stream of new VVIDs (maybe wrapping every 2^32
> > notes - probably OK).  It has it's own internal rules about voice
> > allocation, and probably has less polyphony than 128 (or whatever
> > the host sets).  It can do smart voice stealing (though the LRU
> > algorithm the host uses is probably good enough).  It hashes VVIDs
> > in the 0-2^32 namespace on it's real voices internally.  You only
> > re-use VVIDs every 2^32 notes.
> 
> Ok, but I don't see the advantage of this, vs explicitly assigning 
> preallocated VVIDs to new voices. All I see is a rather significant 
> performance hit when looking up voices.

Where a perf hit?

> Just grab a new VVID and start playing. The synth will decide when a 
> physical voice should be used, just as it decides what exactly to do 
> with that physical voice.

So how does a synth tell the host how it gets activated?  A VOICE_ON event
tells the host and the user 'we are allocating a VVID to use'.  It also
tells the synth.  If the synth wants to not play anything for Velocity <
0.5, then it should just not play anything.  Just because a Voice is silent,
doesn't mean it is not active.  This is a separate discussion entirely from
VVIDs.

> With continous velocity, it is no longer obvious when the synth 
> should actually start playing. Consequently, it seems like wasted 
> code the have the host/sender "guess" when the synth might want to 
> allocate or free voices, since the synth may ignore that information 
> anyway. This is why the explicit note on/off logic seems broken to me.

_Your_ logic seems broken to me :)  If you have a continuous controller for
Velocity, you have one voice.  So you want a new voice, you use a new VVID.
How do you standardize this interface so a host can present a UI that makes
sense?

If VOICE_ON doesn't make sense for some synth, then it still makes sense for
the user.

> > Block start:
> >   time X:	voice(-1, ALLOC)	/* a new voice is coming */
> >   time X:	velocity(-1, 100)	/* set init controls */
> >   time X:	voice(-1, ON)		/* start the voice */
> >   time X:	(plugin sends host 'voice -1 = 16')
> >   time Y:	voice(-2, ALLOC)
> >   time Y:	velocity(-2, 66)
> >   time Y:	voice(-2, ON)
> >   time Y:	(plugin sends host 'voice -2 = 17')
> >
> > From then out the host uses the plugin-allocated voice-ids.  We get
> > a large (all negative numbers) namespace for new notes per block.
> 
> Short term VVIDs, basically. (Which means there will be voice 
> marking, LUTs or similar internally in synths.)

What is LUT?  What is voice-marking?  The negative VVIDs are valid for the
duration of the block, after which they use their new names.  It seems
simple to me.

> > We get plugin-specific voice-ids (no hashing/translating).
> 
> Actually, you *always* need to do some sort of translation if you 
> have anything but actual voice indices. Also note that there must be 

Because the plugin can allocate them, the plugin need not hash or translate.
It can be a direct index.

> a way to assign voice IDs to non-voices (ie NULL voices) or similar, 
> when running out of physical voices.

if voice-ids are allocated by the plugin, there is no NULL voice.  If you
run out of physical voices you steal a voice or you send back a failure for
the positive voice id.

> You can never return an in-use voice ID, unless the sender is 
> supposed to check every returned voice ID. Better return an invalid 
> voice ID or something...

Host:
	send voice_on for temp vid -1
	run
	read events
	    find a voice-id -1 => new_vid
	    if (new_vid < 0) {
	        /* crap, that voice failed - handle it */
	    } else {
	        if (hash_lookup(plug->voices, new_vid)) {
	            /* woops, plugin stole that voice - handle it */
	        }
	        hash_insert(plug->voices, new_vid, something)
	    }

If the plugin wants to steal a voice, do so.  If it wants to reject new
voices, do so.  It is simple, easy to code and to understand.

> Well, it's an interesting idea, but it has exactly the same problem 
> as VVIDs, and doesn't solve any of the problems with VVIDs. The fact 

It has none of the problems of VVIDs.  The only problem is that it requires
dialog.

* no carving of a VVID namespace for controller plugins
* the plugin and the host always agree on the active list of voices
  * host sends voice_off no release
    - plugin puts the VID in the free-list immediately
  - host never sends voice_off
    - plugin puts the VID in the free-list whenever it finishes
    - plugin can alert the host or not
  - host sends events or voice_off too late
    - plugin recognizes that the voice is off and ignores events
  - host sends voice_off with a long release
    - plugin puts the VID in the free-list as soon as possible
  - host overruns plugin's max poly
    - plugin chooses a VID and stops it, returns that VID (steals the voice)
      or plugin rejects new voice

what am I missing?

> search" and/or hashing), and it doesn't really buy us much, compared 
> to the wrapping 32 bit VVID idea.

With a large VVID pool we still need:

host:
  /* be sure we can make a new vvid */
   if (cur_poly == max_poly) {
        find an eligible vvid
        tell the plugin it can re-use the voice on this vvid (voice_off?)
   } else {
        cur_poly++;
   }

   /* find a vvid that is not currently playing */
   do {
        this_vvid = vvid_next++;
   while (vvid_is_active(this_vvid);

   send_event(queue, VOICE_ON, this_vvid);


[voice-stealing...]

> (*Should* work, but it does require click free voice stealing without 

Which is the plugin's problem in any solution we devise.




More information about the Linux-audio-dev mailing list