Midi_clock_beat vs. midi_clock_tick

Trying to control the progression of a hardware synth’s onboard sequencer, I do these at bpm 60, with the synth set to receive MIDI clock, not send MIDI clock, and not receive MIDI Start or Stop:

live_loop :myloop do
  24.times do
    midi_clock_tick port: mySynth
  end
  
  sleep 1.0
end

and

live_loop :myloop do
  midi_clock_beat port: mySynth

  sleep 1.0
end

When externally clocking, the synth’s tempo knob is supposed to affect clock division, not bpm. With the MIDI ticks, the synth’s sequencer progresses at the expected rate, and the synth’s tempo knob has no effect. With the MIDI beats, the synth’s sequencer progresses at a rate that also depends on its tempo knob. I suspect that sound parameters are affected differently per each clocking, but I can’t swear to that right now.

Is there a difference between sending MIDI ticks vs. beats? Is it expected that different hardware combos may handle this kind of clocking from Sonic Pi in their own idiosyncratic ways, or is this aspect of reliability on a par with sending MIDI note on’s and note off’s?

From my reading of the manual:
midi_clock_beat is particular to Sonic Pi and not part of the Midi Spec.
midi_clock_tick is a part of the Midi spec.

The difference is that Sonic Pi’s midi_clock_beat sends 24 ticks every beat to all connected midi devices. You can restrict this behaviour using the port opt, as you have done in your code.

Midi implementations vary between OEMs. for example, some have midi note numbers 0-127 and others 1-128. And that’s just one of the more straightforward issues!

So, Sonic Pi’s midi_clock_beat already sends out 24 ticks, so your 24.times do might be worth commenting out and see if there’s a noticeable difference.

Seems to me that once you have this behaving the way you’d like, you can create variable bursts of ticks to control sequencer progress…

1 Like

Where in the manual do you see that? All I’ve got is, “The MIDI specification requires 24 clock tick events to be sent per beat. These can either be sent manually using midi_clock_tick or all 24 can be scheduled in one go using this fn. midi_clock_beat…”

Interestingly, I’m getting better results (or at least more expected results) clocking the arpeggiator with MIDI beats.

Actually, I really don’t know what it means to send one tick at a time when it comes to controlling the progress of arpeggiators and sequencers. I would think they’d waid on the 24th tick, then trigger the next step so that, in this context, ticks and beat wouldn’t make a difference.

Yes, the midi spec requires it but Sonic Pi’s midi_clock_beat is particular to SPi.

If you look at SPi lang, you can see the inclusion of the relevant Midi Spec version in yellow i.e.
So ’ MIDI 1.0 Specification - System Real-Time Messages - Timing Clock
But midi_clock_beat does not refer and link back tot he Midi Spec, irrespective of version.

Arpeggiators only require a pulse (tick), gate, so are more straightforward.

Which synth’s onboard seq are you using?

I think of the tick/beat distinction as follows, in respect of making a difference:

  1. A tick is a single entity - so to achieve 24 ticks, the code needs to be called 24 times
  2. The beat sends out 24 ticks for the duration of one beat, so only needs to be called once every beat and SPi sends out the 24 ticks

In terms of sequencer behaviour, it varies depending upon how they’ve been implemented. Some sequencers in modular use the rising edge of the pulse and others the falling edge. When they receive the reset pulse this behaviour can also vary. As most soft synths and hardware ‘tend’ to model the capabilities of older sequencer hardware, then this means there will be variability dependant upon which hardware sequencer was modelled.

One of my Eurorack sequencers is the Westlicht Perf|former. This is from their manual regarding midi clocks:
“Note: To set up a 24 PPQN input or output clock resolution, the divisor needs to be set to 2. This is because the divisor is applied to a 48 PPQN resolution instead of the internal 192 PPQN resolution.”
So PPQN is the equivalent of SPi’s tick.

In respect of master clocks, similar to what you’re doing:
" In Restart mode, the master clock is restarted. In Pause mode, the master clock is stopped/resumed."

And the info for these different modes:
" Mode in which to handle the incoming clock control signal. In Reset mode, the clock is kept in reset state while a high signal is read. In Run mode, the clock is only run when the signal is high. In Start/Stop mode, the clock is started when a high signal is read and stopped/paused when a low signal is read."

The reference to high/low signal refer to the state of a clock pulse where the states, assuming 50/50 low/high, sends out either 5 Volts (high) 0 Volts (low).

Of course, any one of my other hardware sequencers will behave differently, which means there isn’t a set and forget approach but instead one that needs to take into account local differences. Therefore ticks can be thought of similarly. When you send a tick it is the equivalent of the pulse sending out a high state. This means the control of these ticks can be in singles, regular, odd, or rapid bursts, dictated to by the sleep value. So a ring of sleep values can be used in this manner:

live_loop :myloop do
    midi_clock_tick port: mySynth
    sleep (ring 0.5, 0.25, 0.125, 0.0625, 0.0625).tick
end

And if you want more variability then you can use choose or pick or use the ring chain commands to create variations.

1 Like

dammit. I was hoping it wouldn’t have to be an investigation and adventure with every hardware synth because I’m working on software stuff with Sonic Pi, and the hardware synths are the just-turn-it-on-and-it-works refuge. I just thought this would be low hanging fruit. I don’t even understand why a sequencer needs any more than the gate that suffices for an arp: just an instruction to proceed to the next step and execute it.

I’m using this with a UDO Super 6, which sounds great, but isn’t the best choice because its design philosophy is to show you no “abstract” information that would trigger your analytical mind to intrude on your musical flow. I have to set its tempo knob by ear when arpeggiating to match its division with the external MIDI clock, and this differs from patch to patch—there are clearly settings going on under the hood that I’d have to get involved with. To mess with ticks and beats, it would be better to have a synth with a screen and easy patch saving and comparison, etc.

I only went this direction because Omnisphere doesn’t have a way to control its tempo when running it standalone. And it inherits the DAW’s tempo when running it as a plugin so that Sonic Pi still could control it directly.

Ah, yes, there will be some differences.

I’ve had a look at the UDO Super 6 page and my understanding is that when set to external clock, control of the Master Tempo acts as a clock divider for the arpeggiator/sequencer. The difference between UDO and Omnisphere is that Omnisphere only has an arpeggiator, a very well spec’d one at that. And yes, you would need to set it’s tempo by hand in standalone mode.

In terms of achieving different tempos, I would suggest using SPi to set tempo locally to each live_loop by using use_bpm. One of the best things, that can lead to some really interesting combinations.

theBPM = 60
live_loop :myloop do
    use_bpm theBPM
    midi_clock_tick port: mySynth1
    sleep (ring 0.5, 0.25, 0.125, 0.0625, 0.0625).tick
end

live_loop :myloop2 do
use_bpm theBPM*3
    midi_clock_tick port: mySyntth2
  sleep 1.0
end

Should work with any external synth, software or hardware.

Hope that helps.

1 Like

Hi there,

TLDR: In short, use midi_clock_beat unless you’re sure you need midi_clock_tick and the upcoming beta will improve the efficiency of this on all platforms and the timing of it on Windows.

Longer Version: For the record, midi_clock_tick will send the specific bytes as defined in the MIDI spec that represents one tick. The MIDI spec also defines that one beat is represented by 24 ticks. This can be understood as a cog with 24 teeth - every time the cog fully rotates round, that represents one beat.

Within the current implementation, Sonic Pi’s Ruby language runtime has to send a message with the specific timestamp for each clock tick. This is then received by the Erlang scheduler which generates the correct MIDI byte representation and then sends it to the specific MIDI device (or all by default) at the specific time.

On less performant machines, this can be a bit problematic due to the way that Sonic Pi is implemented. The Ruby threads will sleep to make sure they’re just around the right (wall-clock) time which leaves very little breathing room for other things to happen - so it’s quite easy for the timing system to stop things because they are running behind time.

The current way of optimising this is to use midi_clock_beat which schedules all 24 ticks using a time_warp block which effectively schedules all 24 ticks in one go without calling sleep. These 24 tick messages all have their specific timestamp and are all scheduled appropriately by the scheduler.

midi_clock_beat is therefore an optimisation over manually calling midi_clock_tick 24 times. It is typically preferred in all known cases. However, midi_clock_tick is in the API because there’s a good chance that non-standard behaviour is required to communicate with some esoteric synths.

Note that in the development version which hopefully should make its way to a Patreon beta next week, I have further optimised midi_clock_beat so that the Ruby runtime only has to send 1 message to the Erlang scheduler, which then generates the 24 messages internally and sends them to the MIDI port.

Also note that on Windows the scheduler is currently less accurate than on macOS or Linux due to some implementation details of Erlang. This introduces around a 10ms jitter which may affect the timing of the clock signal. This accuracy has been addressed in the latest Erlang release which also will be part of the new beta.

1 Like