Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronizing AKPlayer with AKSampleMetronome

Tags:

I am trying to use AKSamplerMetronome as a master clock in my (sort of) multi audiofile playback project. I wanted AKPlayers to be started in sync with Metronome's downbeat. Mixing AKPlayer and AKSamplerMetronome as AudioKit.output was successful, however, I am struggling to connect AKPlayer.start with AKSamplerMetronome.beatTime(or something else I haven't figured out) so the playback starts with the Metronome's downbeat in sync (and repeat every time Metronome hits downbeat). Here's what I've written:

class ViewController: UIViewController {

let metronome = AKSamplerMetronome()
let player = AKPlayer(audioFile: try! AKAudioFile(readFileName: "loop.wav"))
let mixer = AKMixer()

func startAudioEngine() {
    do {
        try AudioKit.start()
    } catch {
        print(error)
        fatalError()
    }
}

func makeConnections() {
    player >>> mixer
    metronome >>> mixer
    AudioKit.output = mixer
}

func startMetronome() {

    metronome.tempo = 120.0
    metronome.beatVolume = 1.0
    metronome.play()
}

func preparePlayer() {

    player.isLooping = true
    player.buffering = .always
    player.prepare()
// I wanted AKPlayer to be repeated based on Metronome's downbeat.

}

func startPlayer() {

    let startTime = AVAudioTime.now() + 0.25
    player.start(at: startTime)

}

override func viewDidLoad() {
    super.viewDidLoad()

    makeConnections()
    startAudioEngine()
    preparePlayer()
    startPlayer()
    startMetronome()

}

}

My problem is that, AKPlayer's start point(at:) doesn't recognize AKSamplerMetronome's properties, maybe because it's not compatible with AVAudioTime? I tried something like:

let startTime = metronome.beatTime + 0.25
player.start(at: startTime)

But this doesn't seem to be an answer (as "cannot convert value type 'Double' to expected argument type 'AVAudioTime?'). It would be extremely helpful if someone could help me exploring Swift/AudioKit. <3

like image 877
Gavin Avatar asked Aug 13 '18 07:08

Gavin


1 Answers

you are calling the AVAudioTime playback function with a Double parameter. That's incorrect. If you want to start the AKPlayer with a seconds param, use player.play(when: time)

In general, you're close. This is how you do it:

    let startTime: Double = 1

    let hostTime = mach_absolute_time()
    let now = AVAudioTime(hostTime: hostTime)
    let avTime = now.offset(seconds: startTime)
    metronome.setBeatTime(0, at: avTime)
    player.play(at: avTime)

Basically you need to give a common clock to each unit (mach_absolute_time()), then use AVAudioTime to start them at the exact time. The metronome.setBeatTime is telling the metronome to reset it's 0 point at the passed in avTime.

like image 124
Ryan Francesconi Avatar answered Sep 28 '22 18:09

Ryan Francesconi