我现在正在寻找这个星期: 我的应用程序需要一个类似功能的节拍器,我用一个线程(复制并改编自Apples Metronom示例),但时机很糟糕。 我知道计时器资源不准确,但我找不到另一种可以使用的技术。 而且我需要短暂的“嘟嘟”声,因此不需要处理完整的音频播放内容。 我将BPM(每分钟节拍数)除以12,以便有可能发挥第八,十六等音符。所以问题不在于音频播放,问题在于两个“滴答”之间的准确时间距离。
这里用于计算滴答距离的代码:
- (double)Be_get12TickDistance:(NSInteger)bpm{
double result = 60.0 / (bpm*12);
return result;
} 线程在这里:
- (void)startDriverTimer:(id)info {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Give sound thread high priority to keep the timing steady
[NSThread setThreadPriority:1.0];
BOOL continuePlaying = YES;
while (continuePlaying) { // loop until cancelled
// Use an autorelease pool to prevent the build-up of temporary date objects
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
SoundEffect *currentSoundEffect= [[self beepAndLEDKeeper] Be_GetBeepSound4CurrentTick:beatNumber theCurrentGroove:grooveNumber];
[currentSoundEffect play];
if ([[self beepAndLEDKeeper] Be_isLEDFlashPoint:beatNumber]){
[self performSelectorOnMainThread:@ selector(setLEDtoHidden:) withObject:[NSNumber numberWithInt:LEDoldBeatNumber+oldGrooveNumber*9] waitUntilDone:NO];
[self performSelectorOnMainThread:@ selector(setLEDtoUnHidden:) withObject:[NSNumber numberWithInt:LEDbeatNumber+grooveNumber*9] waitUntilDone:NO];
LEDoldBeatNumber = LEDbeatNumber++;
}
oldBeatNumber = beatNumber++;
oldGrooveNumber = grooveNumber;
if (beatNumber >= grooveEnd[grooveNumber])
{
beatNumber=0;
LEDbeatNumber=0;
if (++grooveNumber > 1)
grooveNumber=0;
if (grooveEnd[grooveNumber] == 0)
grooveNumber=0;
}
if ([soundPlayerThread isCancelled] == YES)
continuePlaying = NO;
else
[NSThread sleepForTimeInterval:self.duration];
[loopPool release];
}
[pool release];
}
问题: 是否有人提示如何以简单的方式做到这一点? 我只需要更好的计时可能性,SoundEffect的播放就足够了。
感谢您的帮助, 安德烈亚斯
答案 0 :(得分:1)
最简单的解决方案,也是一个非常准确的解决方案,就是使用NSTimer
。我创建了一个简单的演示应用程序来测试它,并且精确到千分之一毫秒(每次计时器选中时我只是NSLog
ged。)
2010-02-07 17:11:07.548 TimerTest[12775:207] Ticked
2010-02-07 17:11:07.648 TimerTest[12775:207] Ticked
2010-02-07 17:11:07.748 TimerTest[12775:207] Ticked
2010-02-07 17:11:07.848 TimerTest[12775:207] Ticked
2010-02-07 17:11:07.948 TimerTest[12775:207] Ticked
2010-02-07 17:11:08.048 TimerTest[12775:207] Ticked
2010-02-07 17:11:08.148 TimerTest[12775:207] Ticked
这是从iPod Touch第二代设备输出的。 (请注意,如果你在此期间进行大量的硬处理,准确度会降低,但我不认为节拍器会有那么多其他事情发生)。计时器来自非常简单的代码:
[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(tick) userInfo:nil repeats:YES];
但我的猜测是,它实际上是引起问题的声音代码。你用什么来播放声音?如果它不是OpenAL,你不能指望它是非常准确的 - 它可以在播放之前,播放之后暂停等。尝试获得一个测试应用程序,看看计时器是否以正确的速率滴答而没有声音和用声音来确定问题的原因。
答案 1 :(得分:0)
一种可行的策略是让后台线程休眠一段固定的时间(例如,每1/16秒)。这使用更准确的CPU时钟,因此当它从通话中返回时,您将更准确。
答案 2 :(得分:0)
NSTimer timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(YOUR_METHOD:) userInfo:nil repeats:YES];
用您想要的任何间隔(以秒为单位)替换scheduledTimerWithTimeInterval:0.1,并用您的方法替换YOUR_METHOD。