Я вижу периодический сбой в моем приложении при остановке секвенсора. В моем приложении используется пользовательский MusicSequencer на основе AudioToolbox с AKMIDISampler, подключенным в качестве его midiEndpoint. Я отследил сбой до того, что AKMIDISampler func handle(event: AKMIDIEvent)
получил пустое событие (то есть event.internalData.count == 0
). Поскольку сэмплер, так сказать, "зашит" как конечная точка, я действительно не уверен, как я могу это отладить, так как я не вижу, что последовательность пытается отправить (или почему она, по-видимому, отправляет пустое событие).
Я смог запустить его, взломав собственную сборку AK, в которой я проверил работоспособность event.internalData.count
. Однако отдельная проблема в моем проекте (https://stackoverflow.com/a/49950129/4321521) заставила меня использовать AudioKit от CocoaPods, удаляющий мой фикс (точнее, хак)...
Я зарегистрировал все свои функции, которые добавляют события в последовательность, и ни одна из них не отправляет пустые данные.
Одно возможное объяснение, о котором мне интересно; Недавно я заметил, что включение AddressSanitizer указывает на переполнение буфера стека при создании пользовательских событий. Признаюсь, я совершенно озадачен тем, как мы собираемся создавать события переменной длины в Swift. Кажется, я не могу «легально» создавать какие-либо события с event.length > 4
, несмотря на то, что структура имеет свойство length
. Например, этот кусок кода:
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]
}
})
дает мне ошибку переполнения буфера стека, когда i == 4
. Поскольку у моего события есть свойство Float64 duration
, это, очевидно, не работает...
Поэтому я полагаю, что моя последовательность неизбежно содержит мусорные данные из-за добавления этих переполненных пользовательских событий. Я просто не понимаю, как это может привести к event.internalData.count == 0
, или почему моя проверка работоспособности на event.internalData
"исправит" это (т. е. запустится без проблем).
Обратный след:
* 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 +
handleMIDI
(которое считывает индексы без проверки границ). Вопрос только в том, что это за пустое событие и как оно туда попадает. Я посмотрю на AKCallbackInstrument. Спасибо за чаевые. На данный момент я создал подкласс AKMIDISampler, добавив проверку границ, чтобы он больше не давал сбоев. - person jbm   schedule 26.09.2018if event.data.count > 2 { // play it }
. Но я должен добавить, что сейчас я использую AKCallbackInstruments, как рекомендовал @c_booth. Все идет нормально. - person jbm   schedule 27.02.2020