MIDI FX for Logic Pro X: Burst of unexpected MIDI data arriving at processBlock in first buffer

Hi guys,

I'm seeing a burst of MIDI nonsense arriving at processBlock in the very first buffer when running any JUCE MIDI FX audiounit in Logic Pro X.

Juce 3.1.1
Xcode 6.1
Logic Pro X 10.1.1

STR

  1. Download my "Velocity Fixer" MFX project
  2. Implement Oscar1771's AU SDK MFX fix/hack as per step 8 of my MIDI FX tutorial
  3. Build and run with Logic Pro X as the executable
  4. Load the included Logic Pro X project
  5. Press play to send some buffers to the "Velocity Fixer" MIDI FX plugin
  6. Take a look at the debug console in Xcode, it'll look something like:
buffer 0 contained a 3 byte MIDI message : 176 100 4 
buffer 0 contained a 3 byte MIDI message : 176 101 0 
buffer 0 contained a 3 byte MIDI message : 176 6 0 
buffer 0 contained a 3 byte MIDI message : 176 100 3 
buffer 0 contained a 3 byte MIDI message : 176 101 0 
buffer 0 contained a 3 byte MIDI message : 176 6 0 
buffer 0 contained a 3 byte MIDI message : 177 100 4 
buffer 0 contained a 3 byte MIDI message : 177 101 0 
buffer 0 contained a 3 byte MIDI message : 177 6 0 
buffer 0 contained a 3 byte MIDI message : 177 100 3 
buffer 0 contained a 3 byte MIDI message : 177 101 0 
buffer 0 contained a 3 byte MIDI message : 177 6 0 
buffer 0 contained a 3 byte MIDI message : 178 100 4 
buffer 0 contained a 3 byte MIDI message : 178 101 0 
buffer 0 contained a 3 byte MIDI message : 178 6 0 
buffer 0 contained a 3 byte MIDI message : 178 100 3 
buffer 0 contained a 3 byte MIDI message : 178 101 0 
buffer 0 contained a 3 byte MIDI message : 178 6 0 
buffer 0 contained a 3 byte MIDI message : 179 100 4 
buffer 0 contained a 3 byte MIDI message : 179 101 0 
buffer 0 contained a 3 byte MIDI message : 179 6 0 
buffer 0 contained a 3 byte MIDI message : 179 100 3 
buffer 0 contained a 3 byte MIDI message : 179 101 0 
buffer 0 contained a 3 byte MIDI message : 179 6 0 
buffer 0 contained a 3 byte MIDI message : 180 100 4 
buffer 0 contained a 3 byte MIDI message : 180 101 0 
buffer 0 contained a 3 byte MIDI message : 180 6 0 
buffer 0 contained a 3 byte MIDI message : 180 100 3 
buffer 0 contained a 3 byte MIDI message : 180 101 0 
buffer 0 contained a 3 byte MIDI message : 180 6 0 
buffer 0 contained a 3 byte MIDI message : 181 100 4 
buffer 0 contained a 3 byte MIDI message : 181 101 0 
buffer 0 contained a 3 byte MIDI message : 181 6 0 
buffer 0 contained a 3 byte MIDI message : 181 100 3 
buffer 0 contained a 3 byte MIDI message : 181 101 0 
buffer 0 contained a 3 byte MIDI message : 181 6 0 
buffer 0 contained a 3 byte MIDI message : 182 100 4 
buffer 0 contained a 3 byte MIDI message : 182 101 0 
buffer 0 contained a 3 byte MIDI message : 182 6 0 
buffer 0 contained a 3 byte MIDI message : 182 100 3 
buffer 0 contained a 3 byte MIDI message : 182 101 0 
buffer 0 contained a 3 byte MIDI message : 182 6 0 
buffer 0 contained a 3 byte MIDI message : 183 100 4 
buffer 0 contained a 3 byte MIDI message : 183 101 0 
buffer 0 contained a 3 byte MIDI message : 183 6 0 
buffer 0 contained a 3 byte MIDI message : 183 100 3 
buffer 0 contained a 3 byte MIDI message : 183 101 0 
buffer 0 contained a 3 byte MIDI message : 183 6 0 
buffer 0 contained a 3 byte MIDI message : 184 100 4 
buffer 0 contained a 3 byte MIDI message : 184 101 0 
buffer 0 contained a 3 byte MIDI message : 184 6 0 
buffer 0 contained a 3 byte MIDI message : 184 100 3 
buffer 0 contained a 3 byte MIDI message : 184 101 0 
buffer 0 contained a 3 byte MIDI message : 184 6 0 
buffer 0 contained a 3 byte MIDI message : 185 100 4 
buffer 0 contained a 3 byte MIDI message : 185 101 0 
buffer 0 contained a 3 byte MIDI message : 185 6 0 
buffer 0 contained a 3 byte MIDI message : 185 100 3 
buffer 0 contained a 3 byte MIDI message : 185 101 0 
buffer 0 contained a 3 byte MIDI message : 185 6 0 
buffer 0 contained a 3 byte MIDI message : 186 100 4 
buffer 0 contained a 3 byte MIDI message : 186 101 0 
buffer 0 contained a 3 byte MIDI message : 186 6 0 
buffer 0 contained a 3 byte MIDI message : 186 100 3 
buffer 0 contained a 3 byte MIDI message : 186 101 0 
buffer 0 contained a 3 byte MIDI message : 186 6 0 
buffer 0 contained a 3 byte MIDI message : 187 100 4 
buffer 0 contained a 3 byte MIDI message : 187 101 0 
buffer 0 contained a 3 byte MIDI message : 187 6 0 
buffer 0 contained a 3 byte MIDI message : 187 100 3 
buffer 0 contained a 3 byte MIDI message : 187 101 0 
buffer 0 contained a 3 byte MIDI message : 187 6 0 
buffer 0 contained a 3 byte MIDI message : 188 100 4 
buffer 0 contained a 3 byte MIDI message : 188 101 0 
buffer 0 contained a 3 byte MIDI message : 188 6 0 
buffer 0 contained a 3 byte MIDI message : 188 100 3 
buffer 0 contained a 3 byte MIDI message : 188 101 0 
buffer 0 contained a 3 byte MIDI message : 188 6 0 
buffer 0 contained a 3 byte MIDI message : 189 100 4 
buffer 0 contained a 3 byte MIDI message : 189 101 0 
buffer 0 contained a 3 byte MIDI message : 189 6 0 
buffer 0 contained a 3 byte MIDI message : 189 100 3 
buffer 0 contained a 3 byte MIDI message : 189 101 0 
buffer 0 contained a 3 byte MIDI message : 189 6 0 
buffer 0 contained a 3 byte MIDI message : 190 100 4 
buffer 0 contained a 3 byte MIDI message : 190 101 0 
buffer 0 contained a 3 byte MIDI message : 190 6 0 
buffer 0 contained a 3 byte MIDI message : 190 100 3 
buffer 0 contained a 3 byte MIDI message : 190 101 0 
buffer 0 contained a 3 byte MIDI message : 190 6 0 
buffer 0 contained a 3 byte MIDI message : 191 100 4 
buffer 0 contained a 3 byte MIDI message : 191 101 0 
buffer 0 contained a 3 byte MIDI message : 191 6 0 
buffer 0 contained a 3 byte MIDI message : 191 100 3 
buffer 0 contained a 3 byte MIDI message : 191 101 0 
buffer 0 contained a 3 byte MIDI message : 191 6 0 
buffer 0 contained a 8 byte MIDI message : 240 127 0 4 3 0 64 247 
buffer 0 contained a 408 byte MIDI message : 240 126 127 8 1 0 76 111 103 105 99 32 84 117 110 105 110 103 0 0 0 0 0 0 0 1 0 0 2 0 0 3 0 0 4 0 0 5 0 0 6 0 0 7 0 0 8 0 0 9 0 0 10 0 0 11 0 0 12 0 0 13 0 0 14 0 0 15 0 0 16 0 0 17 0 0 18 0 0 19 0 0 20 0 0 21 0 0 22 0 0 23 0 0 24 0 0 25 0 0 26 0 0 27 0 0 28 0 0 29 0 0 30 0 0 31 0 0 32 0 0 33 0 0 34 0 0 35 0 0 36 0 0 37 0 0 38 0 0 39 0 0 40 0 0 41 0 0 42 0 0 43 0 0 44 0 0 45 0 0 46 0 0 47 0 0 48 0 0 49 0 0 50 0 0 51 0 0 52 0 0 53 0 0 54 0 0 55 0 0 56 0 0 57 0 0 58 0 0 59 0 0 60 0 0 61 0 0 62 0 0 63 0 0 64 0 0 65 0 0 66 0 0 67 0 0 68 0 0 69 0 0 70 0 0 71 0 0 72 0 0 73 0 0 74 0 0 75 0 0 76 0 0 77 0 0 78 0 0 79 0 0 80 0 0 81 0 0 82 0 0 83 0 0 84 0 0 85 0 0 86 0 0 87 0 0 88 0 0 89 0 0 90 0 0 91 0 0 92 0 0 93 0 0 94 0 0 95 0 0 96 0 0 97 0 0 98 0 0 99 0 0 100 0 0 101 0 0 102 0 0 103 0 0 104 0 0 105 0 0 106 0 0 107 0 0 108 0 0 109 0 0 110 0 0 111 0 0 112 0 0 113 0 0 114 0 0 115 0 0 116 0 0 117 0 0 118 0 0 119 0 0 120 0 0 121 0 0 122 0 0 123 0 0 124 0 0 125 0 0 126 0 0 127 0 0 55 247

Some observations

  • The MIDI burst does seem to originate in the JUCE MFX plugin (I don't think it's coming in from Logic as I cannot re-create the burst unless I have a JUCE MFX plugin inserted)
  • A VST build of the same code does not exhibit the (dare I say it) bug
  • The burst only occurs once after instantiation when processBlock receives the very first buffer
  • The MIDI burst is not always the same

Unfortunately, my knowledge of the inner workings of JUCE and the AU SDK are not sufficient for me to figure this one out on my own, so any input will be massively appreciated.

It's not nonsense, it's a bunch of controller change messages. Presumably Logic sending your plugin the correct values to reset those controllers before it starts processing?

It's not MIDI chase if that's what you mean? I still see the burst even with MIDI chase completely disabled in the project settings. I also don't see the messages if the JUCE MFX is not in the chain.

With an otherwise identical MIDI signal chain, substituting one of Logic's factory MIDI FX for the JUCE one, I see exactly what I'm expecting - MIDI silence until I generate some input.

It really does seem to be getting spuriously generated inside the JUCE plugin - if I stick a MIDI monitor upstream and downstream of my plugin, I will only see the MIDI burst downstream of the JUCE plugin...

Also, did you notice the 8 and 408 byte messages in the buffer?

AFAIK there's no code in juce that will create those messages, it must generated by the host.

Many thanks for your input Jules. In that case I'm doubly confused. I just don't understand how the messages can appear in the middle of the signal chain in between the output of one MIDI FX plugin and the input of the next...

Perhaps JUCE is misinterpreting data it's receiving from Logic (e.g. meta events?) which other Logic AU plugins know to ignore, and then re-generating it as output in such a way that the Logic AU plugins no longer know to ignore?

I certainly wouldn't consider it unlikely that it's a bug in Logic Pro X (as there have been numerous bugs to date), but if it is, it's a bug which only manifests itself (as far as I can tell) with JUCE 3rd party audiounit* MIDI FX plugins. (edit)

Should I just go ahead and tell my plugin to clear the first midiMessages buffer arriving at processBlock? Whilst it would solve this problem, I suspect it could easily cause plenty more...

It's not impossible that there could be a bug that's garbling data, but even then the host must still be sending data for it to garble!

Maybe breakpoint the actual code inside the AU wrapper where midi is received from the host and see what's happening?

Hi again Jules, many thanks for pointing me in the right direction...

I was incorrect - it's not JUCE specific. I downloaded some 3rd party MIDI FX audiounits (Xfer's Cthulu & Audio CR's MIDI Freeze) and they do in fact exhibit similar unexpected behaviour; so it's only Logic's built in MIDI FX audiounits which are immune to this issue.

So now to try and suss out whether it's a bug in Logic Pro X itself, or the AU SDK which (presumably all) 3rd party developers are using.

Difficult to know how best to proceed:

A - Spend lots of time investigating whether it's possible to repair the issue by modifying the AU SDK
B - Report it to Apple, patch it up with a hack, move on and hope it gets fixed down the line by Apple

Re hacks: Is it possible to add JUCE code which only gets compiled into a specific build of a project (e.g. into the audiounit, but not the VST)?

The audio plugins in JUCE are compiled as a single binary, so there is no compile time flag to check for such things. The only way you could do this is by maintaining two seperate projects, which I would strongly advise against.

That said, you could check at runtime if that's helpful to you?