Crash when converting MIDI 1 to MIDI 2

Hi, looks like I’ve had a crash when doing the conversion:

0   AudioToolboxCore              	      0x189657b84 caulk::inplace_function_detail::vtable<void, MIDI::EventList const*>::vtable<APMIDIRouter::handleSetProperty(void*, AudioUnitPluginDispatch const&, unsigned int, unsigned int, unsigned int, void const*, unsigned int)::$_17::operator()(void*, AudioTimeStamp const*, unsigned int, MIDIPacketList const*) const::'lambda'(MIDIPacket const*)::operator()(MIDIPacket const*) const::'lambda'(MIDI::EventList const*)>(caulk::inplace_function_detail::wrapper<APMIDIRouter::handleSetProperty(void*, AudioUnitPluginDispatch const&, unsigned int, unsigned int, unsigned int, void const*, unsigned int)::$_17::operator()(void*, AudioTimeStamp const*, unsigned int, MIDIPacketList const*) const::'lambda'(MIDIPacket const*)::operator()(MIDIPacket const*) const::'lambda'(MIDI::EventList const*)>)::'lambda'(void*, MIDI::EventList const*&&)::__invoke(void*, MIDI::EventList const*&&) + 60
1   AudioToolboxCore              	      0x189581a1c MIDI::LegacyMIDIConverter<MIDI::MIDI_1_to_2_Translator>::convertLegacyDataToEventList(std::__1::span<unsigned char const, 18446744073709551615ul>, unsigned long long, caulk::inplace_function<void (MIDI::EventList const*), 48ul, 8ul>) + 224
2   AudioToolboxCore              	      0x189657a90 APMIDIRouter::handleSetProperty(void*, AudioUnitPluginDispatch const&, unsigned int, unsigned int, unsigned int, void const*, unsigned int)::$_17::__invoke(void*, AudioTimeStamp const*, unsigned int, MIDIPacketList const*) + 156
3   Melody Sauce 2                	      0x14b3f4780 JuceAU::Render(unsigned int&, AudioTimeStamp const&, unsigned int) + 4296
4   Melody Sauce 2                	      0x14b405994 ausdk::AUMethodRender(void*, unsigned int*, AudioTimeStamp const*, unsigned int, unsigned int, AudioBufferList*) + 1508
5   AudioToolboxCore              	      0x18967147c AudioUnitRender + 420
6   AudioToolboxCore              	      0x1895ec3b8 invocation function for block in AUAudioUnitV2Bridge_Renderer::renderBlock() + 628
7   AudioToolboxCore              	      0x1896048d0 void* caulk::thread_proxy<std::__1::tuple<caulk::thread::attributes, AUOOPRenderingServer::AUOOPRenderingServer(int, int, int, std::__1::vector<AudioStreamBasicDescription, std::__1::allocator<AudioStreamBasicDescription>> const&, unsigned int, unsigned int, applesauce::xpc::dict const&, std::__1::shared_ptr<auoop::WorkgroupMirror>)::$_0, std::__1::tuple<>>>(void*) + 2304

Anything I can do to help track this down? Has happened once or twice to a couple of customers, so not a consistent isse.

thx

That looks like it’s crashing inside system code, rather than in JUCE. I think we’d need to know the following:

  • What OS and platform does this happen on? If it’s only on older macOS versions, perhaps it’s already been fixed.
  • What deployment target are you using, and what Xcode version are you using to build released plugins?
  • What’s the sequence of MIDI events that causes the crash?

Hi,
MacOS Ventura 13.4
XCode probably would have been 14.2.x

This is when restoring a project so it’s at plugin load time so not sure what MIDI is going through the system at that point. Trying to get a copy of the project to see if it triggers the issue as not able to reproduce myself.

thx

I’m tracking the same issue on this thread with a repro.

1 Like

I’m able to reproduce this issue with the AudioPluginDemo AUv2 built from develop, in Logic 10.7.8 with MIDI 2.0 enabled:

0   AudioToolboxCore              	       0x18b57fb84 caulk::inplace_function_detail::vtable<void, MIDI::EventList const*>::vtable<APMIDIRouter::handleSetProperty(void*, AudioUnitPluginDispatch const&, unsigned int, unsigned int, unsigned int, void const*, unsigned int)::$_17::operator()(void*, AudioTimeStamp const*, unsigned int, MIDIPacketList const*) const::'lambda'(MIDIPacket const*)::operator()(MIDIPacket const*) const::'lambda'(MIDI::EventList const*)>(caulk::inplace_function_detail::wrapper<APMIDIRouter::handleSetProperty(void*, AudioUnitPluginDispatch const&, unsigned int, unsigned int, unsigned int, void const*, unsigned int)::$_17::operator()(void*, AudioTimeStamp const*, unsigned int, MIDIPacketList const*) const::'lambda'(MIDIPacket const*)::operator()(MIDIPacket const*) const::'lambda'(MIDI::EventList const*)>)::'lambda'(void*, MIDI::EventList const*&&)::__invoke(void*, MIDI::EventList const*&&) + 60
1   AudioToolboxCore              	       0x18b4a9a1c MIDI::LegacyMIDIConverter<MIDI::MIDI_1_to_2_Translator>::convertLegacyDataToEventList(std::__1::span<unsigned char const, 18446744073709551615ul>, unsigned long long, caulk::inplace_function<void (MIDI::EventList const*), 48ul, 8ul>) + 224
2   AudioToolboxCore              	       0x18b57fa90 APMIDIRouter::handleSetProperty(void*, AudioUnitPluginDispatch const&, unsigned int, unsigned int, unsigned int, void const*, unsigned int)::$_17::__invoke(void*, AudioTimeStamp const*, unsigned int, MIDIPacketList const*) + 156
3   AudioPluginDemo               	       0x10d835f00 JuceAU::pushMidiOutput(unsigned int)::'lambda2'()::operator()() const + 80 (juce_audio_plugin_client_AU_1.mm:2152)
4   AudioPluginDemo               	       0x10d8312a8 JuceAU::pushMidiOutput(unsigned int) + 848 (juce_audio_plugin_client_AU_1.mm:2190)

The last line in JUCE code is the body of this lambda. midiCallback is a struct provided by the host.

const auto send = [&]
{
    midiCallback.midiOutputCallback (midiCallback.userData, &lastTimeStamp, 0, packetList);
};

I haven’t dug into this enough to know whether there’s something we can do in JUCE to avoid the crash. I do find it surprising that this code path is even taken - JUCE AUs support the newer MIDIEventList API, and we should only end up calling the line above if the host provides a PacketList callback (old) but not an EventList callback (new).

In fact, when running natively, it looks like Logic does try to supply an EventList callback, but the block it passes is nil, so JUCE doesn’t call it. If I instead run Logic in Rosetta mode, then it doesn’t even try to set the callback.

There definitely seems to be some kind of bug on Apple’s side here. I would expect that the midi callback shouldn’t crash, regardless of the inputs that are passed. The difference in behaviour between the Rosetta/Native versions is also sligtly unexpected.

I’ll try filing a bug report and post here if I hear anything. The Feedback Assistant ID is FB12420223.

Also pinging @mfritze in case this is already a known issue.

1 Like

Seems Logic is not involved in that crash? What does the line juce_audio_plugin_client_AU_1.mm:1964 do?

Thread 3 Crashed:: Dispatch queue: com.apple.NSXPCConnection.user.anonymous.84864
0 libobjc.A.dylib 0x189391c20 objc_msgSend + 32
1 AudioPluginDemo 0x10f697ec8 JuceAU::ScopedMIDIEventListBlock::ScopedMIDIEventListBlock(int (long long, unsigned char, MIDIEventList const*) block_pointer) + 40 (juce_audio_plugin_client_AU_1.mm:1964)
2 AudioPluginDemo 0x10f697e90 JuceAU::ScopedMIDIEventListBlock::ScopedMIDIEventListBlock(int (long long, unsigned char, MIDIEventList const*) block_pointer) + 36 (juce_audio_plugin_client_AU_1.mm:1964)
3 AudioPluginDemo 0x10f697d48 JuceAU::ScopedMIDIEventListBlock::copy(int (long long, unsigned char, MIDIEventList const*) block_pointer) + 44 (juce_audio_plugin_client_AU_1.mm:1947)
4 AudioPluginDemo 0x10f66b4b4 JuceAU::SetProperty(unsigned int, unsigned int, unsigned int, void const*, unsigned int) + 256 (juce_audio_plugin_client_AU_1.mm:668)
5 AudioPluginDemo 0x10f6b2a94 ausdk::AUBase::DispatchSetProperty(unsigned int, unsigned int, unsigned int, void const*, unsigned int) + 2844 (AUBase.cpp:846)
6 AudioPluginDemo 0x10f6bd65c ausdk::AUMethodSetProperty(void*, unsigned int, unsigned int, unsigned int, void const*, unsigned int) + 128 (AUPlugInDispatch.cpp:182)
7 AudioToolboxCore 0x18b59851c AudioUnitSetProperty + 1008
8 AudioToolboxCore 0x18b513eac -[AUAudioUnitV2Bridge setMIDIOutputEventBlock:] + 152
9 AudioToolboxCore 0x18b3e61e4 -[AURemoteHost initialize:reply:] + 848

Sorry about that, I accidentally attached the wrong crash log. I’ve updated the FB issue with a new crash log.

Looked at the new one. My first guess is that it is an issue between your code and macOS – not Logic. Can be Logic, but not my first guess. Looks like a MIDI conversion from MIDI-1 to MIDI-2 is called and the lambda function to be called – and it crashes there. Is it possible that your lambda function is deallocated at that point and it jumps into nowhere?

I can confirm there is no crash with Logic 10.7.4, Apple Silicon, and MIDI 2.0 enabled. I’m not able to test any other versions between 10.7.4 and 10.7.8 as they are difficult to obtain.

I have to confirm, but if our plugin doesn’t produce MIDI output, setting JucePlugin_ProducesMidiOutput to 0, avoids that bit of code that’s crashing in pushMidiOutput and avoids the crash. If again of course, you don’t need MIDI output.

The lambda in question is in a system framework, not provided by JUCE. If the lambda is getting deallocated, there’s not much we can do about it in JUCE. As far as I can tell, JUCE only calls the host-provided MIDI output callback at points where it is valid to do so.

Based on the response here, it sounds like this is confirmed as a bug in CoreAudio (linking here to keep both threads in sync).

@mfritze We ran into this crash as well, and talking to a few other plugin vendors that aren’t using JUCE - they seem to be running into the same crash.