MIDIOut device latency vs Event \lag key

Hi there, I have a fun little Roland S-1 I’m trying to use with SC. The device can function as a USB audio interface, and also can receive MIDI (also over USB).

When trying it out, I was surprised my MIDI-played note events always came before the scsynth-played sounds. I know that the MIDI latency must match the Server latency…it says so in the Sending MIDI out with Patterns helpfile:

If you want to synchronize events played by a MIDI device and events played by the SuperCollider server, the MIDIOut object’s latency must match the server latency. You can set the latency any time to affect all future events.

I set things up like this:

MIDIClient.init;
m = MIDIOut.newByName("S-1", "S-1");

If I check m.latency, it is set to 0.2, the same as my running Server’s s.latency.

(
p = Ppar([
	Pbind(
		\type, \midi,
		\midicmd, \noteOn,
		\midiout, m,
		\chan, 2,
		\degree, Pwhite(-7, 12),
		\dur, 1,
		\amp, 0.7,
	),
	Pbind(
		\instrument, \kick,
		\dur, 1,
		\amp, 0.7,
	)
]).play(quant: 1);
)

When I play events using Event type \midi, I expected the midiout device’s latency to be used. It seems it’s not…I can change m.latency to any value, and there is no change in how (when) my Event Patterns are played on the MIDI device.

I dug into the implementation of the \midi Event type (in Event.makeParentEvents), and I see it has a \lag key, which I can use to do what I want. If I add a \lag key with value m.latency (or s.latency, since they should be the same) in my MIDI Pbind, then I hear correctly synchronized audio-vs-MIDI events on the S-1 device.

I was genuinely surprised that my MIDI Events don’t seem to take the m.latency value into account. I see that in MIDIOut.write (called by MIDIOut.noteOn and friends) it does pass in the latency value. So is it possible there’s something specific with this device and setup? In general, does the MIDIOut latency work for other devices?

Thanks,
Glen.

Actually, a clarification, if I change the tempo, I need to set the \lag key as follows for MIDI Event Patterns, for things to synchronize with Server audio events…

		\lag, Pfunc{ s.latency * TempoClock.default.tempo },

I must be doing something wrong…

The \lag key just delays the message by scheduling it on the current clock.

MIDIOut.latency, on other hand, is directly passed to the MIDI backend in the MIDIOut.send method. Maybe your MIDI backend does not support timestamps and thus just ignores the latency value. I think I’ve heard this before. What’s your OS?

That’s because lag is specified in beats, at least when the pattern is played on a tempo clock, so the actual duration depends on the tempo.

Found it :slight_smile: Midi latency is not effective on Windows · Issue #6047 · supercollider/supercollider · GitHub

What’s your OS?

Dare I say it? Windows (11). (-;

So that would make sense. In that case, I guess my workaround is possibly the only solution?

It also makes sense what you say about scheduling on the TempoClock, since I don’t think it syncs exactly (if I were to record the audio, I’d probably see it), but close enough for my purposes.

Thanks.

I think so… (and some more characters)

Aha, and also it’s mentioned in this thread here, which I didn’t find in my earlier search before posting this question:

Ah, right, now I remember. It is a bug in our portmidi backend. I just put this on my TODO list.

1 Like

Actually, though… \lag is supposed to be in seconds, independent of tempo. It’s in seconds for server-messaging events (see supercollider/SCClassLibrary/Common/Math/SimpleNumber.sc at develop · supercollider/supercollider · GitHub), and documentation says “seconds.”

The problem is that Event implements \lag incorrectly for MIDI, and according to Blaming supercollider/SCClassLibrary/Common/Collections/Event.sc at a36edf848fe3fb7f38a41253528482730839637f · supercollider/supercollider · GitHub, has done so since 2005.

… and nobody noticed, in the last 18 years (suggesting that \lag for MIDI events has not been a widely used feature).

I’ll put in a PR.

hjh

2 Likes

Thanks for checking that, it’s what I’d understood and expected (that lag would be in seconds). And why I was surprised it didn’t work properly once I changed tempo. But when I saw I needed to treat it as beats, I just figured I’d misunderstood it. Good to know otherwise, thanks for digging, @jamshark70 .

Yes, the fact that no one noticed – and that MIDI latency doesn’t work at all on Windows – suggests it’s not really been used in conjunction with scsynth stuff. But I want to use it! :wink:

Fun fact: I’m pretty sure I’ve used \lag with midi, tweaking the value by ear, not paying attention to the actual numerical value…