Sorry for the longevity - I combined 4 emails into one reply :)
>TIMEBASE: (FIXME: instance-constant by host/user
or a dynamic event?)
> - units: ticks/beat (int or float?)
[Paul said...]
float. for all integer tempo/meter setups, we'll
fit things with no
rounding into the 24 bits of a float, yet we'll still allow for other
things as well.
[David said...]
Integer value, at least. Actual format doesn't
matter much, since you
won't see many of these events. (That is, int->float conversion cost
can be ignored.)
So I think that means we use a float control, but suggest int data.
i think that ticks/measure is a nice idea. combined
with ticks/sec for
tempo, you can compute everything you need. however, i don't see how
you can derive the actual western A/B form from just this information,
and this might be necessary for some purposes.
you can't - we'd need to make METER a two-control tuple. Is it really
needed? If so, I suggest we make it int values of the beat-note (quarter is
4.0, thirty-second is 32.0). Isn't this really the domain of the user,
though? What is it used for?
> /* find out the timestamp of the next beat or bar
*/
> uint32_t next_beat = host->time_next(XAP_NEXT_BEAT);
> uint32_t next_bar = host->time_next(XAP_NEXT_BAR);
>
> /* get time info about a timestamp, assuming current tempo, etc */
> XAP_timeval times;
> int r = host->get_time(timestamp, ×,
> XAP_TIME_TICKS | XAP_TIME_WALL | XAP_TIME_SMPTE);
> //FIXME: other time domains?
>
> /* find out what the transport is doing */
> XAP_transport trans = host->get_transport();
i think that having multiple methods to ask about
"current" time is a
mistake. i think that VST's approach is better: have a single function
that retrieves all the information (actually, in VST, you set a
bitfield to specify which information you want). the host doesn't
compute anything till the first call to the function (by a plugin),
thereafter, it uses the precomputed value of the struct that holds the
data. thus:
Not clear - I don't have anything that refers to current time, except
get_transport. I don't know that we should allow mid-block transport stops
(which is why I suggested making transport start/stop be a plugin global
evcent). I split time_next() into a separate function because it has
different semantics than get_time(). Fundamentally there are two functions
I believe are needed
time_next() - get the timestamp of the next beat/bar/...
get_time() - get the timeinfo struct (bitmasked as you suggest) for a
specific timestamp, assuming current tempo/meter/etc.
get_transport() is really useless if transport state is plugin-global, and
useless if it is not. If it is, just get the event. If it is not, put it
into get_time()
i've asked my musician friends, i get two
responses. the rock/pop
people are used to 1 beat = quarter note and tempo =
And most pop/rock/dance will be in QN beats anyway. :)
>What if we had plugin-global notifier events that
told the plugin some
>things:
> TRANSPORT_STATE start/stop events
> TIMEINFO - something time-ish has changed
Now I know that
making some of this plugin-global means that different
channels can't be on different timelines, but honestly, I don't think it
matters :)
i would agree with this. i think its a very sensible idea.
Do we allow mid-block TRANSPORT_STOP ? What does that MEAN? It doesn't
make sense to me...
I am leaning towards one timeline per plugin, not per channel. It is
simpler and I think the loss of flexibility is so marginal as to not matter.
Also, since transport start/stop doesn't make sense mid-block, does it
really make sense as a control? Maybe plug->transport(XAP_TRANSPORT_STOP);
makes more sense?
[David wrote...]
TIMEBASE:
(FIXME: instance-constant by host/user or a dynamic
event?)
Constant for the sequencer at least, I think. (As to GUI level
Is it a constant as in host->timebase, or is it a control that never
changes? Or is it passed to create() like sample rate?
Yep. However, is it assumed that plugins should always
count meter
relative time from where the last METER event was received? I guess
that would be the simplest and "safest" way, although it *does*
reduce musical time accuracy to the sample accuracy level.
We could suggest that hosts send a METER event at each measure-start...
too - special
event TRANSPORT_CTL - parm = start/stop/freeze - do
we really need a special event? see below...
I think we need a special event, since otherwise you can't move the
transport position when the transport is stopped. (See my post on cue
points.)
Maybe moving the transport position (play-head, if you will) should not be
sent to all plugins? If you have Cuepoints (will talk in another thread),
then you have cuepoints. If you don't, you get the TRANSPORT value when
play is resumed.
I'd suggest doing the "host forwards
callbacks to timeline manager"
Yes, when I said "host" I meant "timeline via host struct". As far as
the
plugin is concerned it *is* the host, but it may not actually be.
TEMPO is not special in any way, and nor is transport
start/stop.
Both *can* be normal controls. If they're not, they'll require
special case handling in hosts for defaults and preset handling.
TEMPO and all time controls *are* special. They are not part of a preset,
they are part of the current *studio state*. Saving the TEMPO control with
the preset is wrong.
Yes. (METER would be two controls.)
Only if we need to specify the beat-note, which I don't know.
Either way, I think it's important to keep in mind
that control !=
event. Events are just a transport layer for control data, and other
I think controls should receive <type>_event events only. Sending
'special'
events to controls raises a flag that the design needs more thought.
[David and Frank wrote...]
<lots of stuff about SPEED control>
Hrrm, so is SPEED just a hint to ordinary plugins that they may want to
speed up/slow down their playback because the host is in fast-fwd/rewind
mode? We are adding a lot of levels of indirection for figuring out
anything time/tempo related.
If a host is being fast-forwarded (say 2x) does the TEMPO double, or just
SPEED?
Elucidate, please?
And now for a couple more off-the-wall ideas.
1) SEEK control
If we loop/jump into the middle of a long note, it would be nice to start
playing from the middle. Obviously not all plugins will support it, but
some can (sample players, for instance). How does this sound:
IFF the plugin has a SEEK control:
- Send a VOICE_ON event with timestamp 'now' (same as buffer start)
- Send a voice SEEK event with timestamp 'now' and value
'ticks-to-skip'
= plugin can seek that many ticks into the voice
If the plugin has no SEEK control, it just won't play.
Alternatively, if we use CUEPOINTs for looping, we can use that. Doesn't
fix random jumps, though.
2) another idea wrt TEMPO/METER/POSITION/TRANSPORT/SPEED
All these 'controls' are really broadcasts. They are data transmitted from
the host/timeline to all the plugins in their chain which have the controls.
What if we made it more of a broadcast. Have a way to have host or timeline
global variables (which is what these are) which can be read by plugins.
Plugins have to factor in all the variables whenever they do any calculation
wrt time. We don't want to make it a host callback (function calls are bad,
mmkay). We can make it a global position that plugins read.
When they receive a TIMEINFO event, they need to re-examine some (if they
don't look at them for every sample already). When they receive a TRANSPORT
event, they need to re-examine it (if they care).
Plugins are free to drop these global events. There is no function call
overhead. The only overhead is the indirection of using a pointer to a
global.
Thoughts? Just brainstorming :)
Tim