[linux-audio-dev] XAP and these <MEEP> timestamps...

David Olofson david at olofson.net
Fri Dec 13 19:12:01 UTC 2002


On Friday 13 December 2002 22.14, Tim Hockin wrote:
> > >  Plugins can
> > > look at
> > > host->ticks_per_beat.
> >
> > No, that can change at any time (or many times) in the block.
>
> well, the plugin has to know ticks-per-beat and samples-per-tick. 
> Or rather, samples-per-beat.  If we know samples per beat (tempo)
> we can do whatever we need, right?

Yes - as long as the song position doesn't skip, because that won't 
(*) result in tempo events. Plugins that *lock* (rather than just 
sync) must also be informed of any discontinuities in the timeline, 
such as skips or loops.

(*) You *really* don't want two events with the same timestamp,
    where the first says "tempo=-Inf" and the other says
    "tempo=120 BPM". But that would be the closest to the correct
    way of describing a transport skip you can get. Next is
    "running like hell" for one sample frame, and then reverting
    to the right tempo, but that's a *really* nasty thing to do
    to plugins that are only concerned with tempo...


> Thinking again: A plugin is really concerned with the past, and how
> it affects the future, not the future alone.

That's a good way to explain what prequeueing is really about. :-)


> plugin: "I received
> some event that needs further processing in 1.5 beats".  If it
> knows how many samples per beat, and it receives tempo-change
> events, what more does it REALLY need?  We can provide ticks as a
> higher level of granularity, but is it really needed?

No. I thought some about this earlier, but forgot to write it. This 
is all you need to maintain a perfect (almost - read on) image of the 
timeline:

	Tempo changes
		Whenever the tempo changes, you get a sample
		accurate event with the new tempo.

		Unit: Ticks/sample

	Position changes
		Whenever the song position changes as a result
		of something other than the usual tempo pushing
		it forward, you get an event with the new
		absolute song position.

		Unit: Ticks

	Meter changes
		When PPQN (who would change *that* in the middle
		of a song...?), meter, etc changes, some plugins
		will want to know this, because it affects the
		way they interpret musical time. This event is
		probably best implemented as a notifier that
		gives you a pointer to a static struct owned
		by the sender of the event. (The sequencer, the
		timeline plugin or the host.) (Obviously, this
		means that the sender will have to maintain
		multiple such structs if there are mid-buffer
		changes or multiple changes per buffer!)

		Unit:	*XAP_time_info


That's it! That's all there is to know about the timeline. And you 
don't have to be flooded with any of these events (unless they user 
is abusing the timeline); you'll only get them when something 
interesting happens.

Now, there's one minor problem: Accuracy. If you have a whole song 
playing at the same tempo, the way you calculate musical time 
internally quickly starts to matter. If you do the easiest thing that 
works...

	in the closure:
		float position;
		float tempo;

	in process():
		while(samples left)
		{
			switch(event type)
			{
			  case XAP_A_POSITION_CHANGE:
				position = event->value;
				break;
			  case XAP_A_TEMPO_CHANGE:
				tempo = event->value;
				break;
			}
			for(fragment frames)
			{
				...process audio...
				position += tempo;
			}
		}

...you'll probably drift off pretty soon. *Very* soon! Position 
should definitely be double, or the actual resolution of tempo in the 
addition will approach 0 bits as the difference in exponents 
approaches 24 bits. That means your plugin stops in it's tracks 
within some 6 minutes from start-of-song at 6000 ticks/second. (Hope 
I got the maths right, to within an order of magnitude, at least. :-)

Use double for the events and the internal variables, and you'll be 
"fine" - but it still makes me nervous!

I can see two solutions:

	1) The sender must send "spontaneous" position change
	   events every now and then.

	2) Plugins that care about musical time must resync
	   once per buffer by asking the host about the current
	   musical time.

However, 2 does not work if there's more than one timeline in the 
net, since then, the only thing that can tie anything to the right 
timeline is the events passed to a Channel. A plugin that cares about 
musical time can and should handle one timeline per Channel.

That leaves 1 - and it doesn't seem too bad, performance wise. It's 
not terribly important when these extra resync events are sent; just 
that they're sent "often enough" for everyone to stay within the same 
half audio sample or better.

Position and tempo changes would effectively be controls (although 
changed through specific events), and thus could be handled as such. 
Plugins that care about musical time would have a "fake" Control 
input "TIMELINE" or something on relevant Control Ports, and 
sequencers, timeline plugins and the like would obviously care to 
send the corresponding events only if there is somewhere to send them.


[...]
> plugin:   host->tick_me(100, cookie);  /* alert me in 100 ticks */
> host delivers a tick event at the right time.
>
> I guess I don't really like that.

Interesting idea, though. However, it won't work unless the host is 
the one and only timeline manager, and there is only one timeline.


>  I'd rather see:
>
> plugin recognizes the need for some action in 1/4 beat.
> plugin knows there are 18,900 samples per beat (140bpm @ 44.1k)
> plugin delivers a long-term event to itself for now+4725 samples

That breaks down if there is a tempo change before that event is to 
be delivered. Maybe not a major issue, but it may matter a lot to 
some plugins in some situations.


> This should solve the issue of needing to know the passing of
> linear musical time.  It doesn't solve the need for a plugin to
> know about looping or transports in musical time.

Right.


> Does a plugin
> need to know this?

Yes, definitely.


> Maybe useful for it to go to the middle of a
> sample or something...

Well, that would be possibly, but I don't really expect your average 
synth or sampler to handle that well... It's in fact impossible to 
handle it *correctly*, unless plugins can scan back an get events 
that are before the current position, despite them being skipped.

However, the real reason why you want access to absolute musical time 
is that you need it to lock to the timeline. You can *sync* using 
just tempo, but that's not sufficient if you want to implement beat 
synchronized effects.


//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -'
.- M A I A -------------------------------------------------.
|    The Multimedia Application Integration Architecture    |
`----------------------------> http://www.linuxdj.com/maia -'
   --- http://olofson.net --- http://www.reologica.se ---



More information about the Linux-audio-dev mailing list