将 AKPlayer 与 AKSampleMetronome 同步
Synchronizing AKPlayer with AKSampleMetronome
我正在尝试在我的(某种)多音频文件播放项目中使用 AKSamplerMetronome 作为主时钟。我希望 AKPlayers 与节拍器的节拍同步启动。将 AKPlayer 和 AKSamplerMetronome 混合为 AudioKit.output 是成功的,但是,我正在努力将 AKPlayer.start 与 AKSamplerMetronome.beatTime 连接起来(或其他我还没有弄清楚的东西)所以播放从节拍器的节拍开始同步(并在每次节拍器击中弱拍时重复)。这是我写的:
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()
}
}
我的问题是,AKPlayer 的起始点(at:) 无法识别AKSamplerMetronome 的属性,可能是因为它与AVAudioTime 不兼容?我试过类似的东西:
let startTime = metronome.beatTime + 0.25
player.start(at: startTime)
但这似乎不是一个答案(因为“无法将值类型 'Double' 转换为预期的参数类型 'AVAudioTime?')。如果有人可以帮助我探索 [= =20=].<3
您正在使用 Double 参数调用 AVAudioTime 播放函数。那是不正确的。如果您想使用秒参数启动 AKPlayer,请使用 player.play(when: time)
总的来说,你很接近。这就是你的做法:
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)
基本上你需要给每个单元一个共同的时钟(mach_absolute_time()),然后使用AVAudioTime在准确的时间启动它们。 metronome.setBeatTime 告诉节拍器在传入的 avTime 处将其重置为 0 点。
我正在尝试在我的(某种)多音频文件播放项目中使用 AKSamplerMetronome 作为主时钟。我希望 AKPlayers 与节拍器的节拍同步启动。将 AKPlayer 和 AKSamplerMetronome 混合为 AudioKit.output 是成功的,但是,我正在努力将 AKPlayer.start 与 AKSamplerMetronome.beatTime 连接起来(或其他我还没有弄清楚的东西)所以播放从节拍器的节拍开始同步(并在每次节拍器击中弱拍时重复)。这是我写的:
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()
}
}
我的问题是,AKPlayer 的起始点(at:) 无法识别AKSamplerMetronome 的属性,可能是因为它与AVAudioTime 不兼容?我试过类似的东西:
let startTime = metronome.beatTime + 0.25
player.start(at: startTime)
但这似乎不是一个答案(因为“无法将值类型 'Double' 转换为预期的参数类型 'AVAudioTime?')。如果有人可以帮助我探索 [= =20=].<3
您正在使用 Double 参数调用 AVAudioTime 播放函数。那是不正确的。如果您想使用秒参数启动 AKPlayer,请使用 player.play(when: time)
总的来说,你很接近。这就是你的做法:
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)
基本上你需要给每个单元一个共同的时钟(mach_absolute_time()),然后使用AVAudioTime在准确的时间启动它们。 metronome.setBeatTime 告诉节拍器在传入的 avTime 处将其重置为 0 点。