arirusso / unimidi

Realtime MIDI IO for Ruby
Other
255 stars 28 forks source link

midi-message timing not reliable using Ruby sleep method? #27

Open illtellyoulater opened 10 years ago

illtellyoulater commented 10 years ago

Is there a more reliable way to time midi messages than the Ruby sleep method?

I have written some kind of cpu intensive logic to create beats to play but after many iterations you can feel it has slowly lost tiny fractions of tempo. I admit my code it's not optimized, but, shouldn't midi messages be synchronized through Midi Clock (or something like that?) Do you have any ideas how I can do that? Thanks.

arirusso commented 9 years ago

Sorry for the late response.

This is sort of a "million dollar question". All audio software has this problem to a certain degree, admittedly probably less.

I'm open to any suggestions. One difficulty is that it will most likely have to work differently depending on what platform it is running on.

rubypanther commented 8 years ago

If it is a million dollar question, then I figure late responses are good. ;)

When using midi to interface with hardware digital audio workstations, the midi clock (MTC - Midi Time Code) is sent by the device configured as "master," and that is used for two things; triggering the ADC synchronously so all the tracks are in phase and have correct offsets in the digital file, and also in combination with midi machine control (MMC) codes to give the timestamps additional meaning.

If the platform has a low-res sleep function (many do, many do not) that should cause short-term problems because of rounding or interpolating (which you'd have to handle client-side). Normally the MTC would be sent 30 times a second or something, and you should always be re-syncronizing with the received MTC. The only time you don't need the MTC is when you're using something like a SMPTE time code instead, which is coaxial and not very convenient for computer use.

Without a shared clock, there is no way to maintain tight synchronization without artifacts created during correction.

So finally, conclusions and advice: if you're interfacing with an external midi device, set it to generate MTC and syncronize to that whenever you receive it. If you're not using an external device, you probably want to use some sort of DAW software to generate the MTC and then you can follow that in your software.

illtellyoulater commented 8 years ago

In this case an out of tempo answer is better than no answer :) so thanks guys. But, how can I synchronise to my soundcard MTC using Ruby?

rubypanther commented 8 years ago

It isn't enough to hope that MIDI will correct timing problems; you have to have an MTC clock signal generated by one of your devices. That is a feature that a device has, that you have turned on, or else don't expect it to be there. Many MIDI devices are not designed to be clock masters, and just send events, like keypresses.

Then, once you figure out what clock you're syncing to, you have to do math based on the MTC to calculate your sleep values.

At that point, if your system has low-res sleep then you're still mostly screwed, except that timing won't be off by more than your sleep resolution; without a master clock, drift can accumulate in a less limited fashion. But if you have good system clock resolution, like on most *nix type systems, then you'll be fine.

It may be that you don't need a midi clock at all, you just need to change your sleep call to better calculate the needed sleep time. If it is only out of step with itself, then this is most likely your problem. If it is drifting in reference to your other midi equipment, then you have the other problem above too, and need a midi clock.