【发布时间】:2011-01-13 15:47:12
【问题描述】:
我正在努力在 iPhone 上创建一个简单的节拍器。该应用程序现在所做的是运行一个计时器,每隔 1/1000 秒 秒进入计时器的功能。然后它检查当前时间与启动应用程序的时间(我正在使用CACurrentMediaTime() 函数)。
CFTimeInterval currentTime = CACurrentMediaTime();
if (self.beatingStartTime == 0) {
self.beatingStartTime = currentTime;
}
if ( (currentTime - self.beatingStartTime) >= self.timeIntevalBetweenTicks * self.internalTimerCounter ) {
self.internalTimerCounter ++;
// ...
}
如果有播放音频的好时机,使用 OpenAL 播放它的代码会被触发。
基本上就是这样。我检查了在模拟器和 2 台设备(iPad 和越狱的 iPhone 3GS)上运行时播放的声音,有一个问题 - 当我录制声音并在Reaper 软件中查看波形时,有些声音也播放了一点晚了,其中一些 - 有点太早了(即使我能理解“太晚”的部分,我真的不明白它应该如何更早地播放 - 因为应用程序每次都会检查秒数,它基本上不能比指定的时间更早——但根据我的记录,它确实如此)。
同时,有一些节拍器应用程序在计时方面以“坚如磐石”而闻名,所以我想是有办法的。我只是想知道我错过了什么......
编辑:将计时器调用从 1/1000 秒更改为例如 1/100 秒并没有帮助。
edit 2:当我从计时器切换到线程时(并且我让线程休眠指定的时间),我仍然会遇到奇怪的行为。节奏四处移动,虽然我可以理解有点滞后和播放一些声音太晚,但问题是其中一些确实播放太早 - 这意味着 2 个节拍之间的时间距离小于应该通过。
差异约为 3%,相当于大约 10-15 毫秒,这对我来说是相当多的。有人知道为什么声音可以更早播放吗?我在 iPhone 模拟器和 iPad 实际设备上都试过了,我唯一的猜测是计时器有问题 - CACurrentMediaTime() 返回更多的秒数。甚至可能吗?
【问题讨论】:
-
你为什么使用 OpenAL 而不是简单的 AVAudioPlayer? (您的节拍器需要定位音频吗?)
-
不。但是,当我使用 AVAudioPlayer 之前,我遇到了类似的问题(或者,甚至更糟)。我找到了使用 OpenAL 的建议,因为它最适合在特定时刻播放声音(与粒子游戏帧同步等)。 - 此博客条目benbritten.com/2008/11/06/openal-sound-on-the-iphone 提到“为了更好地控制声音,您将需要 openAL 或 audioUnits 或 audioQueue”)。
-
@kender,另外,您不能每秒调用 1000 次计时器并要求它响应。你在自找麻烦,这就是为什么它似乎永远不会达到目标的原因。即使您将节拍器设置为 16 分音符,速度为 240,您也只需要一个分辨率为 0.015625 秒的计时器。如果不运行您自己的 c 库,您将无法在 iphone 上获得毫秒级的精度,然后就会出现问题。
-
@Kender,你试过 [NSThread setThreadPriority:1.0];如果你优先考虑线程,它应该会稍微稳定你的结果,但是我不相信使用 Core Animation 来处理你的时间是要走的路。动画不需要像您使用它的那样精确。
-
那该用什么?系统时间甚至更不稳定(并且可以在 iPhone 上移动,例如,当它与网络同步时......)