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