More technical details in case anyone wants to improve the MIDI Beat Clock before I have time…
The metronome is updated in the real-time audio thread. It is implemented using an audio stream sample counter. Each time a MIDI Beat Clock message needs to be emitted a message is placed onto the MIDI output queue. This queue is used to pass MIDI messages to the MIDI processing thread that actually writes them to the output device.
Note that timing is already a little suspect here because real-time audio processing is only done periodically, not one sample at a time. An entire buffer of samples is processed in a single operation. For example, with a buffer size of 256 samples at 44100 Hz sample rate the latency is 5.8 milliseconds. So the processing function is only called every 5.8 milliseconds. This means the MIDI Beat Clock would only updated at 5.8 millisecond granularity.
Next, there is a dedicated MIDI processing thread that tries to send/receive MIDI messages every millisecond. All it does is read messages from the MIDI input device and write queued messages to the output MIDI device.
If your computer has sufficient cores then the audio processing and MIDI processing threads run on separate cores with good timing. However, on computers with lower numbers of cores and more applications running (plus other system-level effects related to thread scheduling, interrupts, and timers) it's possible that jammr experiences “jitter” (timing variations).
All this means that the actual timing of emitted MIDI Beat Clock messages will vary.
I suggest looking into the PortMidi (the cross-platform MIDI library that jammr uses) output latency/timestamp features. jammr currently does not use them, but they could solve the problem: the audio thread can assign absolute timestamps to MIDI Beat Clock messages and hopefully PortMidi will emit the messages at the desired time. This should make inter-message time measurement work better in external apps and devices.
The relevant code is NJClient::process_samples() and qtclient/PortMidiStreamer.cpp. Details on getting the code are available here:
https://jammr.net/opensource.html