I'm trying to use AudioKit to playback a sound on each beat of a measure(s). Although I've implemented the code from this similar question regarding callbacks via AudioKit, I can't seem to get the sequencer to update changes and playback properly. It will play once accurately, however after rewinding and changing the values it will only use the initial values (or not playback at all).
My intent is to create a struct of measures with beat values for each measure, then use MIDI and the callback to play different sounds dependent on how many measures/beats there are. Thanks!
import UIKit
import AudioKit
class ViewController: UIViewController {
let sequencer = AKSequencer()
let click = AKSynthSnare()
let callbackInst = AKCallbackInstrument()
// Create the struct that defines each line
struct Line {
var name: String
var measures: Int
var beatsPerMeasure: Int
func totalBeats() -> Int {
return (measures * beatsPerMeasure)
}
}
// Initialize intro line
var intro = Line(name: "Intro", measures: 0, beatsPerMeasure: 0)
// A function to create/update/playback the sequence on button press
func playBack() {
let metronomeTrack = sequencer.newTrack()
metronomeTrack?.setMIDIOutput(click.midiIn)
let callbackTrack = sequencer.newTrack()
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
for steps in 0 ... Int(measuresRowOneValue) {
// this will trigger the sampler on the four down beats
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
// set the midiNote number to the current beat number
callbackTrack?.add(noteNumber: MIDINoteNumber(steps), velocity: 100, position: AKDuration(beats: Double(steps)), duration: AKDuration(beats: 0.5))
// set the callback
callbackInst.callback = {status, noteNumber, velocity in
guard status == .noteOn else { return }
print("beat number: \(noteNumber + 1)")
}
}
}
@IBOutlet weak var rowOneLocationOne: UIImageView!
// Listener for UI display values
var measuresRowOneValue: Int = 0 {
didSet {
intro.measures = measuresRowOneValue
}
}
@IBAction func rowOnePlusButton(_ sender: UIButton) {
measuresRowOneValue += 1
}
@IBAction func rowOneMinusButton(_ sender: UIButton) {
measuresRowOneValue -= 1
}
@IBAction func playbackStart(_ sender: UIButton) {
playBack()
sequencer.play()
}
@IBAction func playbackStop(_ sender: UIButton) {
sequencer.stop()
}
@IBAction func playbackRestart(_ sender: UIButton) {
sequencer.rewind()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
AudioKit.output = click
try!AudioKit.start()
}
}