0

我正在使用 AVAudioPlayer 在我的 iPhone 应用程序中播放音乐。

在我写的一个类中,我有一个包含随机升序整数的数组。(2, 4, 9, 17, 18, 20,...) 这些整数表示歌曲中某个事件应该发生的时间。所以如果你取上面的数组,在歌曲播放 2 秒后,应该调用一些方法。4 秒后,应调用另一个方法。等等。

我尝试使用重复的 NSTimer:

NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerTick) userInfo:nil repeats:YES];

每次触发时,它都会检查 Audioplayer 的值和当前 arrayindex 的值是否相同:

- (void) timerTick {
   if([[myArray objectAtIndex:currentIndex] intValue] == (int)(player.currentTime)) {
   //here the event-method is called
   currentIndex++;
   }
}

这段代码实际上有效,但仅在一段时间内有效。然而,一段时间后,myTimer 和控制音乐播放器的计时器不同步。所以它错过了 myArray 的一个元素并开始了一个无限循环。我不知道它们不同步的确切原因,但我认为这可能是因为计时器和播放器没有在完全相同的时间启动,或者可能是因为短暂的性能滞后。

我想我必须以一种完全不同的方式来处理这个问题。键值观察是一种方法吗?我可以将我的类作为观察者添加到播放器对象,以便在 player.currentTime 值更改时收到通知。但这会导致发送大量通知,我认为这对性能非常不利。

非常感谢任何帮助!

4

3 回答 3

1

好的,这是我的解决方案:我找到了一个开源应用程序,它几乎可以完成我的应用程序应该做的事情,这对我帮助很大。我将坚持使用我已经拥有的代码,稍加修改它应该足以满足我的目的。这里是:

currentIndex = 0;
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerTick) userInfo:nil repeats:YES];


- (void) timerTick {
 if(timerRunning){


     if([[myArray objectAtIndex:currentIndex] intValue] <= (int)(player.currentTime*100)) { 
         //some event code
         currentIndex++;
     }
 }
}

重要的变化是 if 条件中从 == 到 <=。当它变得异步并错过了 myArray 的一个元素时,错误会在接下来的百分之一秒内得到纠正。这已经足够了。

谢谢你的帮助!

于 2009-10-26T20:30:40.710 回答
0

可能是计时器合理地同步,但您的代码只需要很长时间才能执行(即:长于 1 秒)。

难道你不能只使用音乐播放器的计时器,并在每次事件发生时产生一个线程吗?这样计时器就不会被中断,你的线程会做它需要做的事情(比如说繁重的事情)。

如果您真的需要两个计时器,我想您可以创建一个后台线程来使这两个计时器保持同步,但我认为您是在自找麻烦。

于 2009-10-26T11:31:31.343 回答
0

与音乐的真实世界同步非常困难,因为用户可以注意到只有十分之一秒或更短的错误同步。您可能会发现 AVAudioPlayer 对于您需要的东西来说很简单。您可能必须使用AudioQueueServices控制音乐播放的速率,以便您可以将音乐同步到代码,而不是相反。您可以看到启动代码的时间,然后在音乐实际播放之前启动方法。巧妙地完成这将在大部分时间同步音乐。

于 2009-10-26T13:51:55.617 回答