iOS中精确的时序

我在看从iOS SDK(http://developer.apple.com/library/ios/#samplecode/Metronome/Introduction/Intro.html)的“节拍器”示例代码。 我正在节拍器在60 BPM,这意味着滴答每一秒。 当我看到一个外部表(个人电脑的手表),我看到了节拍器速度太慢 - 它错过大约一拍每分钟,这是应用程序。 15msec一致的错误。 相关的代码块是:

- (void)startDriverTimer:(id)info { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Give the sound thread high priority to keep the timing steady. [NSThread setThreadPriority:1.0]; BOOL continuePlaying = YES; while (continuePlaying) { // Loop until cancelled. // An autorelease pool to prevent the build-up of temporary objects. NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; [self playSound]; [self performSelectorOnMainThread:@selector(animateArmToOppositeExtreme) withObject:nil waitUntilDone:NO]; NSDate *curtainTime = [[NSDate alloc] initWithTimeIntervalSinceNow:self.duration]; NSDate *currentTime = [[NSDate alloc] init]; // Wake up periodically to see if we've been cancelled. while (continuePlaying && ([currentTime compare:curtainTime] != NSOrderedDescending)) { if ([soundPlayerThread isCancelled] == YES) { continuePlaying = NO; } [NSThread sleepForTimeInterval:0.01]; [currentTime release]; currentTime = [[NSDate alloc] init]; } [curtainTime release]; [currentTime release]; [loopPool drain]; } [pool drain]; }

哪里

self.duration

为1.0第二次在60 BPM的情况。 我不知道这个错误来自,我怎么能做出更精确的定时器/间隔计数器。

编辑:这个问题的存在,以及当我改变了睡眠时间,以较小的值,例如0.001。

EDIT2(更新):这个问题同样存在,当我使用CFAbsoluteTimeGetCurrent()方法进行计时。 当我用同样的方法来衡量一个按钮点击事件之间的定时,时间似乎准确 - 我点击1次(一边看手表),测量速率为60 BPM(平均)。 所以我想这一定是有问题的NSThread 另一件事是,设备(iPod)的对这个问题似乎更严重,然后在模拟器上。

--------------解决方案-------------

好吧,我有做一些更多的测试后,一些答案,所以我与任何人谁是有兴趣分享。

我已经放在一个变量来衡量刻度之间的时间间隔,里面play的方法(即实际发送的方式play信息的AVAudioPlayer对象),并作为我的简单比较到外部的手表实验表明,在60 BPM是太慢了 - 我有这些时间间隔(以秒为单位):

1.004915
1.009982
1.010014
1.010013
1.010028
1.010105
1.010095
1.010105

我的结论是,一些开​​销时间每1秒的间隔后经过进行计数,并且,额外的时间(约10毫秒)的后一数十秒---为一个节拍器相当坏积累到明显的量。 代替测量呼叫之间的时间间隔的话,我决定测量从所述第一呼叫总的时间间隔,以使误差将不会被累积。 换句话说,我把它换成这种情况:

while (continuePlaying && ((currentTime0 + [duration doubleValue]) >= currentTime1)

与此条件:

while (continuePlaying && ((_currentTime0 + _cnt * [duration doubleValue]) >= currentTime1 ))

那里现在_currentTime0_cnt是类成员(抱歉,如果它是一个C ++行话,我很新的对象- ),前者持有该方法的第一个调用的时间戳,而后者是一个int的刻度计数值(==函数调用)。 这导致了下列测量的时间间隔:

1.003942
0.999754
0.999959
1.000213
0.999974
0.999451
1.000581
0.999470
1.000370
0.999723
1.000244
1.000222
0.999869

而且很明显即使没有算出平均,这些值附近波动1.0秒(平均为接近1.0的精度的至少一毫秒)。

我会很高兴地听到关于是什么原因导致了额外的时间来推移更多的见解 - 10毫秒的声音作为永恒的现代CPU - 虽然我不熟悉的iPod CPU的规格(这是iPod的4G技术,和维基百科说,银联的PowerVR SGX GPU 535 @ 200兆赫)

如果您需要<100毫秒精度,考虑CADisplayLink。 它定期调用一个选择器,尽可能快60倍的第二,即每0.0166667秒。

如果你想要做你的节拍器的测试,你会设置frameInterval为60,因此被称为回来一次第二。

self.syncTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(syncFired:)];
self.syncTimer.frameInterval = 60;
[self.syncTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

-(void)syncFired:(CADisplayLink *)displayLink
{
static NSTimeInterval lastSync = 0;
NSTimeInterval now = CACurrentMediaTime();
if (lastSync > 0) {
NSLog(@"interval: %f", now - lastSync);
}
lastSync = now;
}

在我的测试中,该计时器被称为始终在每0.0001秒秒。

在您与不同的刷新速度比60赫兹的设备上运行的关闭的机会,你必须划分displayLink.duration到1.0,并四舍五入为最接近的整数(而不是楼)。

我对此很感兴趣过,也注意到使用的NSTimer和节拍器的例子的谬误。

我目前正在研究CAMediaTiming协议......但我不知道如何使用它,但它可能被证明是一个更精确的解决方案,因为它是用于动画。 我也可能是完全错误的,因为游戏减缓的时候太多了下去。 我在我最喜欢的游戏我的基础理论,其中精确定时时“战斗在街头的对手”要求。 游戏的FPS已经减少到30,我认为相比,它的控制台同行这时钟的60然而,游戏中的连击系统的时机是非常关键的,比如一个组合包括打一个按钮,然后另外一个正好3帧后的,所以无论是:

  • 在iOS的游戏是计时更宽容
  • 开发商实施了自己的计时系统
  • 否则他们正在使用节拍器的定时器循环或CAMediaTiming协议。

在动画时序信息在这里找到: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Animation_Types_Timing/Articles/Timing.html#//apple_ref/doc/uid/TP40006670-SW1

问题是更根本的。 IOS是不是一个实时操作系统,所以它需要做各种操作的时候是不是“定”。 它而改变。 对于精度就需要像RIM的新QNX操作系统,实时操作系统。

使用whil​​e循环和睡眠时间的节拍器是不是一个可靠的方法来解决这个问题,因为它可能产生的时序是战战兢兢的,而漂移,正如你所看到的。 我认为,解决这个问题的标准方法是使用核心音频(以某种方式)来养活包含您的正确数量的他们之间的沉默,这取决于节奏分离节拍器刻度连续音频流。 因为你知道确切的采样率,你可以在时间的刻度非常精确。 不幸的是,产生音频自己颇有几分比你正在试图做比较困难,但这个问题#1可能让你开始。

非常感谢! 我花了一些时间来找出使用CFAbsoluteTimeGetCurrent()的currentTime0和currentTime1,只好投期限(CGFloat的)分开(双myDuration =(双)持续时间)作为是有一个马试图使用的doubleValue。

你的建议完全适用于我的需要 - 你有没有设法提高准确性?

你有没有考虑使用,而不是这个“怪”,而循环,解决方案的NSTimer? 这似乎对我来说,你是 - 不是只有一点点 - 过分复杂非常非常简单的事情,在这里...

分类:可可触摸 时间:2015-03-15 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.373 (s). 10 q(s)