tempo changes #114
Replies: 10 comments 16 replies
-
My host's tempo editor generates exponential ramps too. They're quantized to MIDI file tempo resolution. For CLAP plugins I send all these events, so the plugin sees exactly what's in the MIDI file. And similar to MIDI files, I assume the plugin doesn't do any interpolation. I agree the comments could tell a bit more about when to send tempo events. |
Beta Was this translation helpful? Give feedback.
-
MIDI file tempo resolution, as I understand it, is "24ths of a microsecond per quarter note". That quantizes the values; I was referring to quantizing when the changes occur. Live uses a remarkably coarse value, apparently. What interval between tempo events do you use when writing SMF? |
Beta Was this translation helpful? Give feedback.
-
I use 8 steps per quarter note. |
Beta Was this translation helpful? Give feedback.
-
If a plugin interpolates the tempo events it could easily go out of sync with the real tempo I think. Is that what you're saying? |
Beta Was this translation helpful? Give feedback.
-
@pauldavisthefirst thanks for the thoughtful idea. Can I ask a couple of questions
Sorry to have questions not answers, but hope those are some constructive thoughts. |
Beta Was this translation helpful? Give feedback.
-
On a related note: I can imagine an extension that lets plugins see the hosts tempo/timesig map. This could also include functions for beat <--> frame conversion, so the host can do the math. There are two ways such an extension would be useful:
|
Beta Was this translation helpful? Give feedback.
-
Let me try to add some perspective from the plug-in side. The timing of built-in sequencers, arpeggiators etc. is usually not such a big deal with tempo changes, as these can typically "snap in" to the PPQ position: "Oh, we're past due time? Fire that NoteOn!" Likewise, host synced delays and such are also no biggie as they need to be smoothed and they're fine as long as the input material is on time. Delays that are adjusted in length will have pitch and comb filters artefacts anyway. Delays that adjust in sample rate are seldom and might drift for a short time when the tempo changes. Depending on feedback, they catch up. The main problem in my experience are tempo synced modulations which can be modulated in rate. For example, take an LFO which is synced to 1/4 but which can be modulated to double speed via aftertouch. It can't be "snapped in" with PPQ position, because that's relative to song start. The solution is to "take it off strict sync" and have it free running. What then happens easily with tempo changes, is a drift. This is the main issue with tempo changes. Furthermore, LFOs and such are typically calculated at control rate, which may be something like 1/16th of the sample rate. So even if tempo ramps were perfectly known to plug-ins, it would be difficult to calculate the correct progression of such a modulator unless control rate and tempo map coincide. I think a really, really good solution would be something as trivial as a very good example implementation of an LFO-style modulator which runs at a common control rate, deals with sudden or smooth tempo changes and finds a way to "snap back in" after a short period of rate modulation (think square wave 4x rate/quarter rate). This example implementation could then serve as test case for hosts as well. |
Beta Was this translation helpful? Give feedback.
-
I feel like from a plugin point of view there's three sensible options for dealing with continuous modulators:
Option 3 is ideal, but can only be done when the next event is known.. so I'd support a proposal that encourages (if not mandates) that hosts send a time event at the very end of the block, at least when there's some tempo-ramp going on (ie. when it's likely you'd otherwise have to snap/chase more than the typical floating point rounding drift). |
Beta Was this translation helpful? Give feedback.
-
One thought on this, just reading the spec the transport event has a tempo and a tempo inc field. Line 223 in e60671b In theory this obviates the need to look ahead in the queue and the job of the host is to send events such that a plugin using piecewise linear interpolation between events of tempo + s * d tempo where s is samples since last event woild sufficiently approximate the underlying tempo curve I hadn’t seen that mentioned in this thread before, and I certainly know surge doesn’t currently use these events accurately (but we can fix that). But I do wonder if from an api design point this solves the problems stated? I’m also going to tag @robbert-vdh since these events are things we should add to the emerging clap validator he is working on |
Beta Was this translation helpful? Give feedback.
-
That said... I guess the original question about exponential (or more generally non-linear) vs. linear ramps is that if you sample the smooth tempo curve at some reasonable modulation rate and send it to the plugin as linear segments (using From the point of view of synchronizing something like LFOs having continuous PPQ time is preferable. From the point of view of something like tempo-synced delays, one could make the case that continuous tempo might be preferable. Personally I feel like if I had to choose one or the other, then continuous PPQ time would probably be preferable most of the time. |
Beta Was this translation helpful? Give feedback.
-
I'd like to start a discussion about handling tempo changes in CLAP. This is not handled adequately by any plugin API, not necessarily because of lack of mechanism, but more through lack of policy.
Prior to CLAP, most plugin APIs could arrange for the host to deliver tempo information to the plugin, and this typically is provided as a single value or tuple corresponding to the tempo at the start of the process() call.
CLAP allows tempo changes to be delivered as events in the queue, which is nice, but only works in a defined way for instantaneous tempo changes. It doesn't really cover the case of tempo ramping adequately.
We've already seen with Ardour that plugins that care about tempo frequently have their own ideas of what tempo ramps look like. Ardour provides them with the value at the start of the process() callback, and the plugins start interpolating over time based on successive values. Note that in Ardour, tempo ramps are continuously valued functions; we do not quantize the changes the way that (e.g.) Live does.
The problems arise from the fact that Ardour honors (apparent) human musical performance behavior, in which tempo ramps are generally exponential, whereas most plugins that do this (that we've seen so far) tend to assume linear ramps. This leads to the host and plugin getting out of sync, which can cause glitches at each process() call as the plugin receives a new (unexpectedly high or low) value from the host.
Since CLAP allows the host to provide multiple tempo events in the queue, one aspect of this problem - quantizating to tempo changes to process() cycle boundaries - is solved.
However, this by itself does not dictate:
I would prefer a solution that (a) does not dictate the shape of tempo ramps (because we believe in what Ardour does, and do not want to fall back to the discrete behavior of DAWs such as Live) (b) somehow allows plugins to function correctly with DAWs with different ideas about ramping (accelerando).
Thoughts?
Beta Was this translation helpful? Give feedback.
All reactions