我试图在Swift中为iOS创建一个节拍器。我使用GCD调度队列为AVAudioPlayer计时。变量machineDelay用于为玩家计时,但其运行速度比我要求的时间慢。
例如,如果我要求延迟1秒,则播放时间为1.2秒。 0.749秒在约0.92秒播放,0.5秒在约0.652秒播放。我可以尝试通过调整这种差异来弥补,但我觉得我在这里缺少了一些东西。
如果有更好的方法完成此操作,请提出建议。这是我的第一个个人项目,所以我欢迎你的想法。
以下是应该适用于此问题的各种功能:
func milliseconds(beats: Int) -> Double {
let ms = (60 / Double(beats))
return ms
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
if self.playState == false {
return
}
playerPlay(playerTick, delay: NSTimeInterval(milliseconds(bpm)))
}
func playerPlay(player: AVAudioPlayer, delay: NSTimeInterval) {
let machineDelay: Int64 = Int64((delay - player.duration) * Double(NSEC_PER_SEC))
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, machineDelay),dispatch_get_main_queue(), { () -> Void in
player.play()
})
}
答案 0 :(得分:2)
我从来没有在iOS上做任何声音,但我可以告诉你为什么你会得到那些不一致的时间。
使用dispatch_after()
时会发生的情况是,某些计时器设置在操作系统的某个位置,并且在它到期后的某个时刻,它会将您的块放在队列中。 "在#34;之后的某个时间点将会很短,但取决于操作系统正在做什么,它几乎肯定不会接近于零。
主队列由主线程使用运行循环进行服务。这意味着您播放声音的任务是竞争使用具有所有UI功能的CPU。这意味着它立即播放声音的可能性非常低。
最后,完成处理程序将在声音播放完毕后的某个短时间内触发,但不一定会立即触发。
所有这些小延迟都会增加您所看到的延迟。不幸的是,根据设备的运行情况,延迟可能会有所不同。这对于需要精确计时的事情永远不会起作用。
我认为,有几种方法可以达到你想要的效果。但是,音频编程超出了我的专业领域。您可能想从Core Audio开始。我的五分钟研究表明音频队列服务或OpenAL,但这五分钟实际上是我在iOS上所知道的所有声音。
答案 1 :(得分:0)
dispatch_after不适用于示例准确的回调。
如果您正在编写音频应用程序,则无法逃脱,您需要以一种或另一种方式实现一些CoreAudio代码。
它将“抽取”特定数量的样本。做数学(象征性地;)