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.