AFAIK there is no signature info in either MIDI clock or MIDI time code - clock just sends ticks, time code sends quarter frames, and SPP sends a position in 16th notes from the start of the sequence.
The only signature info defined in the MIDI standard is the meta info embedded in MIDI files.
So to my knowledge the signature info needs to be set within Cantabile - I know of no way to override that externally…
Hmm… this might be a major clue. So what happens if external clock starts the transport while Cantabile’s meter is 4/4, and then a binding or state change changes the meter to 6/8 while the external clock just keeps ticking along? I assume some weird timing results?
If so, this seems to imply that back-to-back song changes with differing meters are prone to sync failures, since the meter (internal source) and clock tick rate (external source) probably don’t change at exactly the same moment… ?
Playback sends clock stop/start when the song count-in begins, but it sounds like you’re saying that position will only stay correct if I already have Cantabile’s meter set correctly when the clock start/stop message arrives. If I don’t change the meter fast enough (e.g., if I switch to the proper meter during the song count-in), then I’ll be off-sync until the next clock stop/start.
If that’s a correct explanation, then I guess I need to find a way to do meter-changes exactly at external clock start. But a binding can’t work because bindings fire slightly after the triggering MIDI event.
In fact… I can’t think of how any meter change during a running, externally sync’ed transport could ever result in desirable behavior. Meter changes can’t be received over MIDI, so they can’t possibly be synchronized with an external clock, so they’ll always result in incorrect synchronization if they occur while the external transport is running, right?
But what happens if the clock source doesn’t do that? What does Cantabile do when the meter changes while the transport source is external MIDI clock and it’s already playing with no intervening clock start/stop or reposition messages?
I would assume that Cantabile will try to deal with the signature change constructively; this could be to either
switch to “1” with the next “tick” after the change of signature, whenever that occurs
Switch to “1” on the next quarter or eighth note (or whatever the new signature base is), according to the current tempo
Given @brad’s thoughtful nature, I would assume the second, since the first is a bit brute force
What you need to be aware of: MIDI clock has no concept of a “1” or a start of a measure - it simply sends identical 'ticks" 24 times per quarter note. That helps to keep multiple devices at the same TEMPO, but not on the same BEAT.
To get multiple devices to sync to the same beat, you need additional information. Typically, you either use Start/Stop so everyone starts on the same beat, or you use Song Position Pointer to specify a position in 1/16th notes from the start - but that again is ignorant of any signature…
TBH, I think your setup seems too complex on one hand and too incomplete (in terms of information transmitted from the central playback system) on the other to reliably and robustly “slave” Cantabile to the master…
I’d suggest to either de-couple your Cantabile setup from the master and ensure that you can sync “manually” somehow (e.g. tempo set in Cantabile song info, and Arpeggiators triggered manually) or to re-work things from the master side so that each song reliably sends the start/SPP info that Cantabile needs to start in sync… and even then, given the nature of the MIDI sync mechanisms, I’m not sure I would trust this for live use…
There’s another possibility too: Instead of switching to “1”, Cantabile might try to preserve the current position but use the new meter henceforth (unless the current position is at a beat number that exceeds the new meter’s denominator?). I don’t know – probably only @brad knows for sure.
But if I were to recommend what I think Cantabile should do…
I think the only transport position that is both computable and results in possibly intended behavior is a reinterpretation of the current position according to the new meter:
Let m be the current measure number, b be the current beat number (which might be fractional), and n1/d1 be the current meter.
The current song-time (in d1th notes) is therefore t1 := (m-1)n1+(b-1).
At the moment that the meter changes to n2/d2, the transport position should jump to song-time t2 := (d2/d1)t1 (measured in d2th notes).
So the transport should jump to beat (t2 mod n2)+1 of measure floor(t2/n2)+1.
This is the only way I can think of to accommodate the problem that meter changes cannot be precisely synchronized with external clocks. The clock source can send a stop/start, and maybe even a reposition, but it can’t send the meter change. That means that the only thing a Cantabile song can possibly do to change meters mid-song is via a binding or state-change that will inevitably fire slightly after whatever message the clock sends to signal the change. The above formula computes the only possibly intended transport position without requiring Cantabile to deal with any special cases for how late the meter change might occur, or what other things might happen in the meantime. It’s (I think) the only possible transport position that can make sense given the available information.
My setup is, for better or worse, the one that almost universally pervades medium-to-large churches in the US these days. Multitracks+Playback is what they use for their backing tracks, so I have to support it. Playback sends MIDI clock and SMPTE timecode, and Cantabile doesn’t read SMPTE, so MIDI clock is the only option. Tempo-sync’ed LFOs & arps are a core part of many modern worship tunes, so I can’t neglect them. And it’s almost impossible to sync them manually; clock sync is essential. I resort to manual sync as a fallback when I can’t get Cantabile to cooperate, and it’s much more error-prone than MIDI clock. Human response time plus MIDI latency plus no jitter correction makes it a hot mess.
Most of my fellow worship keys players use Mainstage as their slave DAW, and somehow it gets the MIDI clock sync right even when Cantabile doesn’t. I don’t know what it’s doing differently, but somehow it works.
Thing is, most keys players I talk to aren’t very happy with Mainstage. They wish they could do what I do with Cantabile. But they’ll never switch as long as Cantabile can’t MIDI clock sync reliably. I wish I could figure out why Cantabile’s sync occasionally doesn’t behave as expected, because I think it would open a significant new pool of Cantabile subscribers. When Cantabile does sync properly, it’s beautiful (more rock solid than Mainstage). But when it doesn’t work, it’s a glaring train wreck.
After much testing over the past month, I’m ready to make a recommendation for @brad:
Recommendation:When transport is set to external clock sync and playing (not stopped), meter changes should not jump the transport position to beat 1. They should instead preserve the MIDI Song Position Pointer (SPP) (i.e., jump to whatever measure and beat number the preserved SPP equals under the new meter).
Reasoning: When a user sets the transport to external clock sync, she wants the external clock to control the transport’s position as defined by the SPP, including all start, stop, position, and tick messages. Jumping the transport to beat 1 on meter changes breaks that functionality because it overrides the SPP with an unsynchronized event. It’s unsynchronized because meter changes are slave-local events (e.g., binding targets, UI events, etc.) that are arbitrarily time-displaced from any external events that may have triggered them. Jumping to beat 1 at that arbitrary instant desynchronizes Cantabile from the external master, breaking the external clock sync.
Two example breaking scenarios:
I’m playing background music in 4/4 time. The director starts the count-in for the next song (including master clock start, which drives the backing track). I switch to the appropriate song in my playlist, which is in 6/8, and I’m ready to hit the first chord at the end of the count-in. But I’m already doomed. My SPP was correct until Cantabile jumped to beat 1 at some random moment when I hit the song-change button, and now my SPP doesn’t match the master’s SPP henceforth.
The Christmas Medley switches from Silent Night (3/4 time) to Jingle Bells (4/4 time) at measure 136. So the master sends a clock-stop, song-reposition, program-change, and clock-continue message sequence at the start of measure 136, and I make a Cantabile binding that switches to 4/4 time in response to the program-change message. Unfortunately, the binding cannot fire exactly at the triggering event; there’s a tiny delay. The meter-change therefore occurs slightly after the clock-continue, corrupting the SPP again.
In both cases, correct behavior can only be achieved by preserving the SPP, and I would argue that preserving the SPP is the only action that obeys the MIDI clock protocol. In particular, changing the meter should never change the SPP as it’s defined by the external clock; it should only affect how Cantabile interprets the master-defined SPP value (in terms of measure and beat number).
Some Math: Preserving the SPP in terms of meter and beat numbers probably looks like this:
In general, when the meter is n/d, an SPP value of p (measured in 16th notes) corresponds to:
measure(p,n,d) = floor((pd/16) / n) + 1
beat(p,n,d) = ((pd/16) mod n) + 1
A meter change from n1/d1 time to n2/d2 time at SPP position p should therefore jump the transport from beat beat(p,n1,d1) of measure measure(p,n1,d1) to beat beat(p,n2,d2) of measure measure(p,n2,d2). This preserves the SPP p.
Note that this preserves fractional values of p (which is important since meter changes can occur at arbitrary times not aligned to 16th notes).
While I agree with all this, it’s not a simple fix. The biggest issue is that when switching songs, Cantabile (probably incorrectly) tears down the MIDI clock listener, stops the current transport and loads the next song. In the new song, the old MIDI clock listener has already been destroyed, and the transport starts in a “stopped” state.
So, while the math is pretty simple to work out the new transport position, transferring that between songs is not.
As for time signature changes within the current song - the current position doesn’t reset, but the calculated bar/measure is recalculated as if that time signature had been in place the whole time - so it jumps. Again not ideal.
I’m currently working on a major refactor of some other core parts of Cantabile’s audio engine. I’m not sure if these changes will help with this, but I’d prefer get that work finished before diving deeper into this.
Thanks for looking into this (and happy holidays!).
I think you’re right. To conform to the MIDI clock protocol, I think slaves must persistently track what the clock-master thinks the SPP equals, as defined by the history of all MIDI start, tick, stop, reposition, and continue messages received. Ideally this should be tracked even when the transport source is internal, so that the SPP can be jumped to the master’s position if/when the clock source is switched to external.
There are probably extreme circumstances when this is impossible (e.g., when the user reconfigures ports or stops the audio engine), but it seems reasonable to tell users not to do such things live if they need sync. I personally don’t even need it to work while switching songs (since I put all my chained song-sets into one giant Cantabile “song”), but most users probably would.
That’s what I think correct behavior should do, but it’s not what I observe. To preserve the SPP, slaves must indeed jump the transport to a beat+measure that equals the master-defined SPP with the slave-defined meter. Any other behavior would either violate the SPP or violate the meter. But whatever beat+measure is currently recalculated by Cantabile at meter changes is incorrect. My meter changes almost always put Cantabile in a different transport position than the master. In case it matters, my meter changes are usually produced by song-state changes (never by song changes).
The biggest problem I can see with time signature changes while MIDI Clock sync is running is getting the timing right. If you want the measure numbers to increment naturally across a time signature change, the exact point in time of the time signature change is important.
Given that song and state changes take time I’m not sure how this can be done precisely enough to guarantee an accurate transition.
I agree that measure numbers cannot increment naturally across time signature changes, since the MIDI clock standard does not permit it. The standard seems to say that the slave’s SPP must remain equal to the master’s, irrespective of meter.
But I don’t think Cantabile correctly preserves the SPP at meter changes. Here’s why: Even in songs where the master’s meter never changes (e.g., remains 4/4 throughout), if I change Cantabile’s meter to the master’s meter (e.g., change from 6/8 to 4/4) partway into the song, my downbeats do not match the master’s throughout the remainder of the song. If Cantabile’s SPP matched the master’s SPP, the downbeats should align, right?