> I personally find this notion bizarre and
counter-intuitive. The
> idea that the note is turned on by some random control is just
> awkward. I'm willing to concede it, but I just want to be on the
> record that I find it bizarre.
The way I see it, this "random control" that
triggers a note is
equivalent to MIDI NoteOn. It can even be a standardized NOTE control
that all synths must respond to, one way or another.
OK - in my own notes I had been referring to it as the VOICE control. You
send the VOICE control a VOICE_ON message and a VOICE_OFF message, or
simpler send 0 and 1.
comprehend,
and more consistent. I want to toss MIDI, but not
where the convention makes things easy to understand. I think that
explaining the idea that a voice is created but not 'on' until the
instrument decides is going to confuse people. Over engineered.
I think the alternative would render continous control synths even
more confusing. "Why do I have to send a VOICE_ON to make the synth
work at all?"
Anyway, it's really an implementation issue. Just
don't mention it in
the API docs. Just say that the NOTE control corresponds to MIDI
NoteOn/Off. Problem solved!
So stroking the NOTE control in your mind is *identical* to sending a 1 to
the VOICE control in my mind.
The plugin CAN
use the VVID table to store flags about the voice,
as you suggested. I just want to point out that this is
essentially the same as the plugin communicating to the host about
voices, just more passively.
Only the host can't really make any sense of the data.
If flags are standardized, it can. Int32: 0 = unused, +ve = plugin owned,
-ve = special meaning.
It seems
useful.
Not really, because of the latency, the polling requirement and the
coarse timing.
When does the host allocate from the VVID list? Between blocks. As long as
a synth flags or releases a VVID during it's block, the host benefits from
it. The host has to keep a list of which VVIDs it still is working with,
right?
If the plugin
can flag VVID table entries as released, the host can
have a better idea of which VVIDs it can reuse.
Why would this matter? Again, the host does *not* do physical voice
management.
You can reuse a VVID at any time, because *you* know whether or not
you'll need it again. The synth just doesn't care, as all it will
right, but if you hit the ned of the list and loop back to the start, you
need to find the next VVID that is not in use by the HOST. That can include
VVIDs that have ended spontaneously (again, hihat sample or whatever). The
host just needs to discard any currently queued events for that (expired)
VVID. The plugin is already ignoreing them.
This is where the confusion/disagreement is, I think:
I don't
think of this event as "INIT_START", but rather as
"CONTEXT_START". I don't see the need for a specific "init" part
of the lifetime of a context. Initialization ends whenever the
synth decides to start playing instead of just tracking controls.
Right - this is the bit I find insane. From the user perspective:
I want to start a note. Not whenever you feel like it. Now. Here
are the non-default control values for this voice. Anything I did
not send you, assume the default. Go.
So, bowed string instruments, wind instruments and the like are
insane designs? :-)
No, they just might not have init params. The voice is started when the bow
contacts the string.
A bowed string instrument is "triggered" by
the bow pressure and
speed exceeding certain levels; not directly by the player thinking
Disagree. SOUND is triggered by pressure/velocity. The instrument is ready
as soon as bow contacts the string.
The difference
comes when the host sends the 'magic' start-voice
control too soon.
Assume a synth with a bunch of init-latched controls.
Assume velocity is the 'magic trigger'.
time0: Host sends VOICE_START/ALLOC/whatever
time0: Host sends controls A, B, C (latched, but no effect from
the synth) time0: Host sends control VELOCITY (host activates
voice)
time0: Host sends controls D, E, F (ignored - they are
init-latched, and init is over!)
Do you see the problem?
No, I see a host sending continous control data to an init-latched
synth. This is nothing that an API can fix automatically.
Ok, let me make it more clear. Again, same example. The host wants to send
7 parameters to the Note-on. It sends 3 then VELOCITY. But as soon as
VELOCITY is received 'init-time' is over. This is bad. The host has to
know which control ends init time. Thus the NOTE/VOICE control we seem to
be agreeing on.
Yes, it has to be triggered by a standardized control,
so hosts
and/or users will know how to hook synths up with sequencers,
controllers and other senders.
Precisely.
If it has no voice controls, there will be no VVIDs.
You can still
allocate and use one if you don't want to special case this, though.
Sending voice control events to channel control inputs is safe, since
the receiver will just ignore the 'vvid' field of events.
I think that if it wants to be a synth, it understands VVIDS. It doesn't
have to DO anything with them, but it needs to be aware. And the NOTE/VOICE
starter is a voice-control, so any Instrument MUST have that.
has killed the voice. Thus, no need for a
"VOICE_END" or similar
event either.
The host still has to be able to end a voice, without starting a
new one.
Why? What does "end a voice" actually mean?
It means that the host wants this voice to stop. If there is a release
phase, go to it. If not, end this voice (in a plugin-dpecific way).
Without it, how do you enter the release phase?
From the sender
POV:
I'm done with this context, and won't send any more events
referring to it's VVID.
No. It means I want the sound on this voice to stop. It implies the above,
too. After a VOICE_OFF, no more events will be sent for this VVID.
From the synth
POV:
The voice assigned to this VVID is now silent and passive,
More, the VVID is done. No more events for this VVID. The reason that
VVID_ALLOC is needed at voice_start is because the host might never have
sent a VOICE_OFF. Or maybe we can make it simpler:
Host turns the NOTE/VOICE on.
It can either turn the NOTE/VOICE off or DETACH it. Here your detach name
makes more sense. A step sequencer would turn a note on, then immediately
detach.
assumed to be more special than it really is.
NOTE/VOICE_ON/VOICE_OFF
is a gate control. What more do you need to say about it?
Only if you assume a voice lives forever, which is wasteful. Besides that,
a gate that gets turned off and on and off and on does not restart a voice,
just mutes it temporarily. Not pause, not restart - mute.
control. But
until then we need a consistent way to handle
init-latched controls. Because they ARE special. They all need to
be sent before the voice is activated.
Yes - just like you have to send MIDI Program Change *before* playing
notes. It's not really a continous control, but MIDI sequencers don't
special case it, since it's obvious enough that the user should say
what sound he/she wants *before* starting to play.
Well, you CAN change Program any time you like - it is not a per-voice
control.
YES! The same
as a VOICE_ON. or send a 1 to the VOICE control.
Describe it how you will, it tastes like VOICE_ON. Remember before
when I said I would concede this point? I lied! I might concede
VVIDs and give up on plugin-allocated VIDs, but this seems more and
more right, and you yourself talked me back into it.
Well, then we can probably conclude that most of this is a matter of
terminology confusion. :-)
MOSTLY. We still have agree on the problem of init- and release-latched
controls. See below.
Either way, what I'm trying to figure out is a way
to have both
note-on latched and continous control synths do sensible things even
if the sender doesn't know which type it's dealing with.
Of course. See below again :)
I don't
like
that. Perhaps release velocity is a different control.
Yes, I think so.
Release velocity is a release-latched control.
Control set events can have three forms (a control can handle any
combination of them by flags or something):
1) events that apply to the starting of the voice
2) events that apply to an active voice
3) events that apply to the ending of an event
Controls which are init-latched ONLY (e.g. velocity for a velo map) need to be
grouped together before the voice is started.
Controls which are release-latched ONLY (e.g. release velocity) need to be
grouped together before the voice is ended.
We need to standardize the way of sending these.
Idea 1: as we've been discussing, have some window during which events are
KNOWN to be init (or release).
-- INIT:
send VOICE_INIT(new_vvid) /* declare a vvid */
send SET(new_vvid, ctrl) /* set controls for init */
send VOICE_ON(new_vvid) /* start the vvid */
-- RELEASE:
send VOICE_DEINIT(vvid) /* going into release */
send SET(vvid, ctrl) /* set controls for release */
send VOICE_OFF(vvid) /* do release */
Idea 2: similar to idea 1, but less explicit.
-- INIT:
send SET(new_vvid, ctrl) /* implicitly creates a voice */
send VOICE_ON(new_vvid) /* start the vvid */
-- RELEASE:
send SET(new_vvid, ctrl) /* send with time X */
send VOICE_OFF(vvid) /* also time X - plug 'knows' it was for release */
Idea 3: different events for init/release/active sets.
Of those, I like #1. It feels familiar. You declare a variable before you
use it, and you unlink something before you kill it.
#2 init is ok. I don't like the release. #3 is not pretty.
we're gettig there...
Tim