I'm seeing an intermittent crash in my app when stopping the sequencer. My app uses a custom AudioToolbox-based MusicSequencer, with the AKMIDISampler connected as its midiEndpoint. I've tracked the crash down to AKMIDISampler's func handle(event: AKMIDIEvent)
getting an empty event (i.e., event.internalData.count == 0
). Because the sampler is "hard-wired", so to speak, as the endpoint, I'm really not sure how I can debug this, since I can't see what the sequence is trying to send (or why it's apparently sending an empty event).
I was able to get it running by hacking my own AK build, in which I sanity check event.internalData.count
. However, a separate issue in my project (https://stackoverflow.com/a/49950129/4321521) has forced me to use AudioKit from CocoaPods, which removes my fix (or rather, hack)...
I've logged all my functions that add events to the sequence and none of them appear to be sending empty data.
One possible explanation that I'm wondering about; I've recently noticed that enabling AddressSanitizer indicates a stack-buffer-overflow when creating user events. I'll admit that I'm totally mystified as to how we're intended to create variable-length events in Swift. I can't seem to "legally" create any events with event.length > 4
, despite the fact that the struct has a length
property. For example, this bit of code:
let eventDataBytes = ByteBackpacker.pack(event) // convert to [UInt8]
var midiData = MusicEventUserData()
midiData.length = UInt32(MemoryLayout<Event>.size)
withUnsafeMutablePointer(to: &midiData.data, { pointer in
for i in 0 ..< eventDataBytes.count {
print("Can write byte \(i)...")
pointer[i] = eventDataBytes[i]
}
})
gives me a stack-buffer-overflow error when i == 4
. Since my Event has a Float64 duration
property, this obviously doesn't work...
So I suppose it's inevitable that my sequence has garbage data in it, from adding these overflowed user events. I just don't see how that would lead to event.internalData.count == 0
, or why my sanity check on event.internalData
would "fix" it (i.e., run without issues).
The backtrace:
* thread #10, stop reason = EXC_BREAKPOINT (code=1, subcode=0x100bc677c)
frame #0: 0x0000000100bc677c Spliqs`partial apply for closure #1 in AKMIDISampler.enableMIDI(_:name:) [inlined] generic specialization <Swift.UInt8> of Swift.Array._getElement(Swift.Int, wasNativeTypeChecked: Swift.Bool, matchingSubscriptCheck: Swift._DependenceToken) -> A at AKMIDISampler.swift:0 [opt]
frame #1: 0x0000000100bc677c Spliqs`partial apply for closure #1 in AKMIDISampler.enableMIDI(_:name:) [inlined] generic specialization <Swift.UInt8> of Swift.Array.subscript.getter : (Swift.Int) -> A at AKMIDISampler.swift:0 [opt]
frame #2: 0x0000000100bc677c Spliqs`partial apply for closure #1 in AKMIDISampler.enableMIDI(_:name:) [inlined] AudioKit.AKMIDISampler.(event=AudioKit.AKMIDIEvent @ 0x00007f94f2693800)(event: AudioKit.AKMIDIEvent) throws -> () at AKMIDISampler.swift:60 [opt]
* frame #3: 0x0000000100bc677c Spliqs`partial apply for closure #1 in AKMIDISampler.enableMIDI(_:name:) at AKMIDISampler.swift:48 [opt]
frame #4: 0x0000000100bc677c Spliqs`partial apply for closure #1 in AKMIDISampler.enableMIDI(_:name:) at AKMIDISampler.swift:0 [opt]
frame #5: 0x0000000100bc4bb8 Spliqs`thunk for @escaping @callee_guaranteed (@unowned UnsafePointer<MIDIPacketList>, @unowned UnsafeMutableRawPointer?) -> () at AKMIDISampler.swift:0 [opt]
frame #6: 0x0000000194f6d7ac CoreMIDI`LocalMIDIReceiverList::HandleMIDIIn(unsigned int, unsigned int, void*, MIDIPacketList const*) + 156
frame #7: 0x0000000194f6d608 CoreMIDI`MIDIProcess::RunMIDIInThread() + 124
frame #8: 0x0000000194f81640 CoreMIDI`XThread::RunHelper(void*) + 20
frame #9: 0x0000000194f85698 CoreMIDI`CAPThread::Entry(CAPThread*) + 88
frame #10: 0x0000000184c25220 libsystem_pthread.dylib`_pthread_body + 272
frame #11: 0x0000000184c25110 libsystem_pthread.dylib`_pthread_start + 292
frame #12: 0x0000000184c23b10 libsystem_pthread.dylib`thread_start +