Search code examples
iosaudiokit

How to make AKSequencer to stop automatically if it reached the end of the sequence?


I noticed that the AKSequencer continue playing (AKSequencer.isPlaying is true) even when there is no more notes to play in the sequence. Is it possible to make it auto-stop at the end of the sequence?


Solution

  • You can use AKMIDICallbackInstrument to trigger code based on the content that your sequencer is playing. In this case, add an additional track and set it's output to AKMIDICalllbackInstrument. Add an event to this track at the position that you want your sequencer to stop at (you can use sequencer.length if you don't know already know how long it is). Then set up the callback instrument's callback function to stop the sequencer when the event is received.

    var seq = AKSequencer()
    var callbackInst: AKMIDICallbackInstrument!
    var controlTrack: AKMusicTrack!
    
    func setUpCallback() {
        // set up a control track
        controlTrack = seq.newTrack()
    
        // add an event at the end
        // we don't care about anything here other than the position
        controlTrack.add(noteNumber: 60,
                         velocity: 60,
                         position: seq.length,
                         duration: AKDuration(beats: 1))
    
        // set up the MIDI callback instrument
        callbackInst = AKMIDICallbackInstrument()
        controlTrack?.setMIDIOutput(callbackInst.midiIn)
    
        // stop the sequencer when the control track's event's noteOn is recieved
        callbackInst.callback = { statusByte, _, _ in
            guard let status  = AKMIDIStatus(statusByte: statusByte) else { return }
            if status == .noteOn {
                self.seq.stop()
            }
        }
    }