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

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: Re: [linux-audio-dev] XAP and these timestamps...
From: David Olofson (david_AT_olofson.net)
Date: Sat Dec 14 2002 - 02:06:46 EET


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


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Sat Dec 14 2002 - 02:11:57 EET