如何在播放音乐文件期间让动画在精确点工作?
How to get animation to work at exact points during playback of a music file?
Question:
In Swift code, apart from using an NSTimer
, how can I get animations
to start at exact points during playback of a music file played using AVFoundation
?
背景
我有一种使用 AVFoundation
播放音乐文件的方法(如下)。我也有 UIView 动画,我想在播放音乐文件期间的确切点开始。
我可以实现此目的的一种方法是使用 NSTimer
,但这有可能会不同步或不够准确。
有没有一种方法可以让我利用 AVFoundation
访问音乐文件的流逝时间(计时器),以便当音乐播放过程中的某些点到达时,动画开始?
是否有 AVFoundation
触发的事件/通知提供自音乐文件开始播放以来经过的持续时间流?
例如
在0:52.50(52秒1/2),调用startAnimation1()
,在1:20.75(1分20秒3/4),调用startAnimation2()
,等等?
switch musicPlayingTimeElapsed {
case 0:52.50:
startAnimation1()
case 1:20.75:
startAnimation2()
default:
()
}
正在使用 AVFoundation
播放音乐
import AVFoundation
var myMusic : AVAudioPlayer?
func playMusic() {
if let musicFile = self.setupAudioPlayerWithFile("fileName", type:"mp3") {
self.myMusic = musicFile
}
myMusic?.play()
}
func setupAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer? {
let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
let url = NSURL.fileURLWithPath(path!)
var audioPlayer:AVAudioPlayer?
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: url)
} catch {
print("AVAudioPlayer not available")
}
return audioPlayer
}
您可以尝试使用键值观察来观察声音播放时的持续时间 属性。当持续时间达到您的时间阈值时,您将触发每个动画。您需要使时间阈值匹配时间 >= 触发时间,因为您可能无法与所需时间完美匹配。
不过我不知道它的效果如何。首先,我不确定声音播放器的持续时间是否符合 KVO。
其次,KVO 有点占用资源,如果您的 KVO 侦听器每秒被调用数千次,它可能会使事情陷入困境。至少值得一试。
如果你使用AVPlayer
而不是AVAudioPlayer
,你可以使用(TBH有点尴尬)addBoundaryTimeObserverForTimes
方法:
let times = [
NSValue(CMTime:CMTimeMake(...)),
NSValue(CMTime:CMTimeMake(...)),
NSValue(CMTime:CMTimeMake(...)),
// etc
];
var observer: AnyObject? = nil // instance variable
self.observer = self.player.addBoundaryTimeObserverForTimes(times, queue: nil) {
switch self.player.currentTime() {
case 0:52.50:
startAnimation1()
case 1:20.75:
startAnimation2()
default:
break
}
}
// call this to stop observer
self.player.removeTimeObserver(self.observer)
我解决这个问题的方法是事先将音乐分成不同的片段。然后我使用以下两种方法之一:
我一次播放一个片段,每个片段都有自己的音频播放器。当一个片段结束时,音频播放器的代表会收到通知,因此开始下一个片段——以及伴随的动作——由我决定。
或者,我将所有片段排队到 AVQueuePlayer 上。然后我在队列播放器的 currentItem
上使用 KVO。因此,当我们移动到新段时,我会准确地得到通知。
Question:
In Swift code, apart from using an
NSTimer
, how can I get animations to start at exact points during playback of a music file played usingAVFoundation
?
背景
我有一种使用 AVFoundation
播放音乐文件的方法(如下)。我也有 UIView 动画,我想在播放音乐文件期间的确切点开始。
我可以实现此目的的一种方法是使用 NSTimer
,但这有可能会不同步或不够准确。
有没有一种方法可以让我利用 AVFoundation
访问音乐文件的流逝时间(计时器),以便当音乐播放过程中的某些点到达时,动画开始?
是否有 AVFoundation
触发的事件/通知提供自音乐文件开始播放以来经过的持续时间流?
例如
在0:52.50(52秒1/2),调用startAnimation1()
,在1:20.75(1分20秒3/4),调用startAnimation2()
,等等?
switch musicPlayingTimeElapsed {
case 0:52.50:
startAnimation1()
case 1:20.75:
startAnimation2()
default:
()
}
正在使用 AVFoundation
import AVFoundation
var myMusic : AVAudioPlayer?
func playMusic() {
if let musicFile = self.setupAudioPlayerWithFile("fileName", type:"mp3") {
self.myMusic = musicFile
}
myMusic?.play()
}
func setupAudioPlayerWithFile(file:NSString, type:NSString) -> AVAudioPlayer? {
let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
let url = NSURL.fileURLWithPath(path!)
var audioPlayer:AVAudioPlayer?
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: url)
} catch {
print("AVAudioPlayer not available")
}
return audioPlayer
}
您可以尝试使用键值观察来观察声音播放时的持续时间 属性。当持续时间达到您的时间阈值时,您将触发每个动画。您需要使时间阈值匹配时间 >= 触发时间,因为您可能无法与所需时间完美匹配。
不过我不知道它的效果如何。首先,我不确定声音播放器的持续时间是否符合 KVO。
其次,KVO 有点占用资源,如果您的 KVO 侦听器每秒被调用数千次,它可能会使事情陷入困境。至少值得一试。
如果你使用AVPlayer
而不是AVAudioPlayer
,你可以使用(TBH有点尴尬)addBoundaryTimeObserverForTimes
方法:
let times = [
NSValue(CMTime:CMTimeMake(...)),
NSValue(CMTime:CMTimeMake(...)),
NSValue(CMTime:CMTimeMake(...)),
// etc
];
var observer: AnyObject? = nil // instance variable
self.observer = self.player.addBoundaryTimeObserverForTimes(times, queue: nil) {
switch self.player.currentTime() {
case 0:52.50:
startAnimation1()
case 1:20.75:
startAnimation2()
default:
break
}
}
// call this to stop observer
self.player.removeTimeObserver(self.observer)
我解决这个问题的方法是事先将音乐分成不同的片段。然后我使用以下两种方法之一:
我一次播放一个片段,每个片段都有自己的音频播放器。当一个片段结束时,音频播放器的代表会收到通知,因此开始下一个片段——以及伴随的动作——由我决定。
或者,我将所有片段排队到 AVQueuePlayer 上。然后我在队列播放器的
currentItem
上使用 KVO。因此,当我们移动到新段时,我会准确地得到通知。