I've started experimenting with AudioKit - lovely framework, however I'm having some crashes that I can't trace.
To get started, I wanted to build a sequencer and I followed the example in this medium post: https://medium.com/@oleary.audio/building-a-midi-sequence-in-swift-bed5f5c2bb7d and also added some code to help visualise the current step played in the sequencer, using a callback instrument (as described here: AudioKit ios AKSamplerMetronome).
Everything is running fine when I am in the app, however if I exit and leave the app in the background and re-enter, it randomly (once every 4-5 tries) crashes with a stack trace that I don't understand (see below)
I'm not sure what might be causing this, or what might be calling the AKMIDIInstrument.enableMIDI function I'm seeing in the debugger. Any tips on this are greatly appreciated.
EDIT: I have to add that this only happens on a physical device, I haven't been able to reproduce it in the simulator.
EDIT2: I've also tried moving the callback instrument's callback function outside of the view controller and setting up a delegate to change the view, thinking that the view controller's lifecycle might affect it in some way, but the issue still persists.
Here's a simplified version of my code for reference:
class AudioCore {
static let sharedInstance = AudioCore()
let osc = AKOscillatorBank()
let sequencer = AKSequencer()
let callbackTrack:AKMusicTrack?
let soundTrack:AKMusicTrack?
let callbackInstrument = AKCallbackInstrument()
let midi = AKMIDI()
init() {
let midiNode = AKMIDINode(node: osc)
AudioKit.output = midiNode
do {
try AudioKit.start()
}
catch {
AKLog("Audio kit failed to start")
}
if let track = sequencer.newTrack(){
callbackTrack = track
callbackTrack?.setMIDIOutput(callbackInstrument.midiIn)
} else {
callbackTrack = nil
}
if let sound = sequencer.newTrack(){
soundTrack = sound
soundTrack?.setMIDIOutput(midiNode.midiIn)
} else {
soundTrack = nil
}
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
for i in 0...10 {
AudioCore.sharedInstance.soundTrack?.add(noteNumber: MIDINoteNumber(pitch), velocity: 127, position: AKDuration(beats: pos), duration: AKDuration(beats: dur))
AudioCore.sharedInstance.callbackTrack?.add(noteNumber: MIDINoteNumber(i), velocity: 127, position: AKDuration(beats: pos), duration: AKDuration(beats: dur))
}
AudioCore.sharedInstance.callbackInstrument.callback = { status, note, vel in
guard status == .noteOn else { return }
DispatchQueue.main.async {
if(note < self.buttons.count) {
self.buttons[note].backgroundColor = UIColor.red
}
}
let dispatchDelay = 1.0 / tempo * 60.0 * noteLength
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + dispatchDelay, execute: {
if(note < self.buttons.count) {
self.buttons[note].backgroundColor = oldColor
}
})
}
}
}