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