[英]iOS, swift: play background music and sound effects without delay
I am trying to create a game in iOS without using SpriteKit. 我试图在不使用SpriteKit的情况下在iOS中创建游戏。 I am stuck in getting the sound effects to play in a timely manner.
我一直无法及时播放声音效果。 I've been using the following code which I have found online and the background music plays great.
我一直在使用以下代码,这些代码是我在网上找到的,背景音乐播放效果很好。 However, when I use the "playSoundEffect" method it plays ok the first time but then starts to lag behind and becomes out of sync.
但是,当我使用“ playSoundEffect”方法时,它第一次播放正常,但随后开始滞后并变得不同步。 I guess that happens because it initializes an AVAudioPlayer every time.
我猜想是因为它每次都会初始化AVAudioPlayer。 Anyone have a good idea in how to play sound effects in a timely manner, while also playing background music?
在及时播放声音效果的同时,还播放背景音乐的人有一个好主意吗? Thanks!
谢谢!
import AVFoundation
public class SKTAudio: NSObject, AVAudioPlayerDelegate {
public var backgroundMusicPlayer: AVAudioPlayer?
public var soundEffectPlayer: AVAudioPlayer?
private var mainLoopFileName:String! {
let randomSong = Int(arc4random_uniform(3))
switch randomSong {
//case 0: return "Test.mp3"
//case 1: return "Test2.mp3"
case 0: return "SneakySnitch.mp3"
case 1: return "FasterDoesIt.mp3"
case 2: return "MonkeysSpinningMonkeys.mp3"
default:
break
}
return "SneakySnitch.mp3"
}
public class func sharedInstance() -> SKTAudio {
return SKTAudioInstance
}
public func playBackgroundMusic() {
let filename = mainLoopFileName
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
if (url == nil) {
println("Could not find file: \(filename)")
return
}
var error: NSError? = nil
backgroundMusicPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
if let player = backgroundMusicPlayer {
player.numberOfLoops = 0
player.delegate = self
player.prepareToPlay()
player.play()
} else {
println("Could not create audio player: \(error!)")
}
}
public func pauseBackgroundMusic() {
if let player = backgroundMusicPlayer {
if player.playing {
player.pause()
}
}
}
public func resumeBackgroundMusic() {
if let player = backgroundMusicPlayer {
if !player.playing {
player.play()
}
}
}
public func playSoundEffect(filename: String) {
let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
if (url == nil) {
println("Could not find file: \(filename)")
return
}
var error: NSError? = nil
soundEffectPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
if let player = soundEffectPlayer {
player.numberOfLoops = 0
player.prepareToPlay()
player.play()
} else {
println("Could not create audio player: \(error!)")
}
}
// MARK: AVAudioPlayerDelegate
public func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
println("finished playing \(flag)")
delay(5.0, {
self.playBackgroundMusic()
})
}
public func audioPlayerDecodeErrorDidOccur(player: AVAudioPlayer!, error: NSError!) {
println("\(error.localizedDescription)")
}
}
You could using AVPlayer to play your sound file. 您可以使用AVPlayer播放声音文件。 Keep one player, but change its
AVPlayerItem
to a new item when you need to play a new sound. 保留一个播放器,但在需要播放新声音时将其
AVPlayerItem
更改为新项目。 It might be faster than recreating the player every time. 它可能比每次重新创建播放器都要快。
While AVAudioPlayer
/ AVPlayer
is the simplest option, it will not give you the shortest delay or perfect synchronization when playing audio files. 虽然
AVAudioPlayer
/ AVPlayer
是最简单的选项,但是在播放音频文件时,它不会给您最短的延迟或完美的同步。 You should look into Audio Queues or Audio Units within Core Audio for more accurate sound playback. 您应该查看Core Audio中的 Audio Queue或Audio Units,以获得更准确的声音播放。
The problem is that you are playing the second sound effect before the first one is finished. 问题是您要在第一个音效完成之前播放第二个音效。 You are killing the reference to the first when you set the new
AVAudioPlayer
to your soundEffectPlayer
variable and the first will stop playing. 当您将新的
AVAudioPlayer
设置为soundEffectPlayer
变量时,您将终止对第一个的引用,并且第一个将停止播放。
If you don't mind loosing the availability of controlling the volume of the sound you could use this: 如果您不介意失去控制音量的可用性,则可以使用以下方法:
var mySound: SystemSoundID = 0
AudioServicesCreateSystemSoundID(url, &mySound)
// Play
AudioServicesPlaySystemSound(mySound)
Otherwise you can use AVAudioPlayer
if you add each sound that you create into an array, keeping the reference. 否则,如果将创建的每个声音添加到数组中,并保留引用,则可以使用
AVAudioPlayer
。 Then you can delete it when the sound is done by implementing AVAudioPlayer
delegate. 然后,当实现声音后,可以通过实现
AVAudioPlayer
委托将其删除。
func playSound(){
let path : NSString? = NSBundle.mainBundle().pathForResource("sound", ofType: "wav")!
let url = NSURL(fileURLWithPath: path!)
var error : NSError?
let sound = AVAudioPlayer(contentsOfURL: url, error: &error)
sound.delegate = self
sound.volume = 0.5
self.soundsEffectsArray.addObject(sound)
sound.prepareToPlay()
sound.play()
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
self.soundsEffectsArray.removeObject(player)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.