I am new to AudioKit and programming music app. I'm building a metronome app and using AudioKit's AKMetronome. I want to have a feature where a user can specify a sequence of beat patterns with different tempo. But I find it is inaccurate to use apple's DispatchQueue.
I'm thinking of rewriting the metronome using AKSequencer. Is there a way to use AudioKit's sequencer to change tempo on the fly or generate a sequence with multiple different tempo? (Sequencer example: https://github.com/AudioKit/Cookbook/blob/main/Cookbook/Cookbook/Recipes/Shaker.swift)
metronome.tempo = 120
let first_interval = 60.0 / 120.0
let switchTime1 = DispatchTime.now() + (first_interval * 4.0)
metronome.play()
DispatchQueue.main.asyncAfter(deadline: switchTime1, execute: {
self.metronome.tempo = 200
})
let second_inter = 60.0 / 200.0
let switchTime2 = switchTime1 + (second_inter * 8.0)
DispatchQueue.main.asyncAfter(deadline: switchTime2, execute: {
self.metronome.tempo = 120
})
Update:
I figured out that you can assign a callback function to AKMetronome using AKMetronome.callback. (https://audiokit.io/docs/Classes/AKMetronome.html#/s:8AudioKit11AKMetronomeC8callbackyycvp) You can then update the tempo at the start of a new sequence.
A possible solution would be to create a tempo track, which would contain tempo events that when processed change the sequencer's tempo.
This is an outline of what should be done:
It’s a little difficult to represent the tempo value inside a MIDI event because usually, MIDI parameters go from 0 to 127. What I would do is use a Note On
event, in the note's pitch I would store tempo div 128
and in the note's velocity, tempo % 128
.
This is what your callback function would look like:
func tempoCallback(status:UInt8, note:MIDINoteNumber, vel:MIDIVelocity) -> () {
guard let status = AKMIDIStatus(byte: status),
let type = status.type,
type == .noteOn else { return }
let tempo: Int = note * 128 + vel
sequencer.tempo = Double(tempo)
}