arirusso / unimidi

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

Numerous crashes on OSX. #35

Open MrJoy opened 8 years ago

MrJoy commented 8 years ago

Versions

In short, it appears to be the case that if I send messages 'too fast', I get a segfault in a subsequent transition between native code and Ruby (commonly Thread.sleep, but I've seen it happen in other very random places too suggesting that the VM is pre-empting plain Ruby code to service another thread and kaboom).

My current working hypothesis is that the CoreMIDI buffer fills up, and error handling is not a thing that is being done in such a scenario. Looking at the CoreMIDI API, it looks like it's the callers' responsibility to gate themselves using a completion callback, etc.

The problem here is that in some cases I know with absolute certainty that I can robustly send MIDI messages to the particular device much more quickly than I can apparently manage with UniMIDI. For example, using portmidi, I can update every LED on the grid of a Novation Launchpad Mark 2 in RGB mode (sysex payloads are much longer for this; I wind up sending two sysex messages to do a full-board update*) at a rate of about 45hz. Using UniMIDI, things seem generally stable only if I gate it to about 12hz or less.

Proposed Solution

  1. Is there a way to tell CoreMIDI to push messages more quickly? If so, that would be helpful.
    • Note that while it schedules messages based on timestamp, merely setting timestamp to 0 does not appear to help at all. Perhaps setting the message to be slightly in the past would, but I haven't tried that yet.
  2. Implement completion callbacks, and block on sending new messages until the last one is completed. Alternatively if there's some known buffer size behind the scenes that can be controlled or whose size can be queried, block only when it fills up and only until there's room for the next message.

    Reproduction

I don't have a great isolated test case, at the moment, but the code I'm working on is here:

https://github.com/MrJoy/surface_master/tree/unimidi_experiment

Specifically, see the examples directory and commit history for those files. The Numark Orbit ones are a bit misleading as I have both the problem of CoreMIDI backlogging and causing a segfault but also a 'soft' issue of the Orbit getting stuck and going into la-la land if I send things too quickly -- but not quickly enough to trigger the fault.