使用GCD dispatch_after快速计时

时间:2015-12-24 05:02:09

标签: ios swift grand-central-dispatch

我试图在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()    
    })
}

2 个答案:

答案 0 :(得分:2)

我从来没有在iOS上做任何声音,但我可以告诉你为什么你会得到那些不一致的时间。

使用dispatch_after()时会发生的情况是,某些计时器设置在操作系统的某个位置,并且在它到期后的某个时刻,它会将您的块放在队列中。 "在#34;之后的某个时间点将会很短,但取决于操作系统正在做什么,它几乎肯定不会接近于零。

主队列由主线程使用运行循环进行服务。这意味着您播放声音的任务是竞争使用具有所有UI功能的CPU。这意味着它立即播放声音的可能性非常低。

最后,完成处理程序将在声音播放完毕后的某个短时间内触发,但不一定会立即触发。

所有这些小延迟都会增加您所看到的延迟。不幸的是,根据设备的运行情况,延迟可能会有所不同。这对于需要精确计时的事情永远不会起作用。

我认为,有几种方法可以达到你想要的效果。但是,音频编程超出了我的专业领域。您可能想从Core Audio开始。我的五分钟研究表明音频队列服务或OpenAL,但这五分钟实际上是我在iOS上所知道的所有声音。

答案 1 :(得分:0)

dispatch_after不适用于示例准确的回调。

如果您正在编写音频应用程序,则无法逃脱,您需要以一种或另一种方式实现一些CoreAudio代码。

它将“抽取”特定数量的样本。做数学(象征性地;)