Not exactly related, but on Windows note also that latency
key doesn’t work with \midi
Events.
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 …
opened 09:10PM - 24 Jun 23 UTC
bug
## Environment
* SuperCollider version: 3.12.1
* Operating system: Windows
… * Other details (Qt version, audio driver, etc.):
## Steps to reproduce
Create this class:
```supercollider
LinkToMidiClock {
var <midiOut, <linkClock, routine, <isPlaying = false, d;
*new { arg midiOut, linkClock;
^super.newCopyArgs(midiOut, linkClock)
}
start {
if(isPlaying,{
"Can't start. LinkToMidiClock is already playing".inform;
},{
isPlaying = true;
d = 1/24;
routine = Routine {
midiOut.start;
loop {
23.do { |i|
midiOut.midiClock;
d.wait;
};
midiOut.midiClock;
(thisThread.clock.beats.ceil - thisThread.beats).wait;
}
}.play(~clock, [linkClock.quantum, 0]);
});
}
stop {
if(isPlaying,{
isPlaying = false;
midiOut.stop;
routine.stop;
},{
"Can't stop. LinkToMidiClock is not playing".inform;
})
}
}
```
And then run this code:
```supercollider
IDIClient.init;
~mymidi = MIDIOut.newByName("the-midi-device", "the-midi-device");
~clock = LinkClock.new.latency_(0.1);
~myclock = LinkToMidiClock(~mymidi, ~clock);
~myclock.start;
~myclock.stop;
```
## Expected vs. actual behavior
I expect to be able to shift the timing of the clock by adjusting the
latency parameter. I tried multiple different latencies but all seemed to produce the same result.
As pointed out by jamshark in https://scsynth.org/t/midi-clock-out-separate-process-for-better-stability/5089/3 it seems like there could be a bug because Linux and Mac pass a latency to their backends but Windows does not. Quoting him here:
> I looked at the source code, and it looks to me like it could be a bug.
>
> We support MIDI in three platforms:
>
> * macOS: “late” (latency) is a parameter used when adding the MIDI message to a MIDIPacketList (C++ CoreMIDI object, you won’t > find this in the class library).
> * Linux: “late” is a parameter for the ALSA MIDI function sendEvent().
> * Windows: The message is sent by the PortMIDI function Pm_WriteShort(). This function accepts a timestamp. Presumably this should be calculated from the current time + latency, but our code does not do that.
>
> The argument in favor of considering it a bug is that, just because it’s harder to handle latency in PortMIDI doesn’t make it OK to not do it.
>
> I’m not in a position to fix it, though. If anyone is interested and has C++ chops, look at prSendMIDIOut() at SC_PortMIDI.cpp line 741. Here, at the end of the function, we should determine what is the PortMIDI timestamp for “now” (I don’t have details on how to do that, you’d have to read PortMIDI references by yourself), then, where the Pm_WriteShort() call specifies 0 as the timestamp, instead do now + late (I guess).
I resorted to a sending the Midi clock from a different Link capable software so I no longer need this fixed but I thought it could be good to report the issue so that it becomes known. Feel free to close the ticket if there's no time to fix it.
I mention this because if you’re using MIDI on Windows and also need to “shift” timing a bit to make hardware devices sync up with the Server, then you need to use a workaround.