iOS:如何在没有fps下降的情况下播放音频? [英] iOS: How to play audio without fps drops?

查看:143
本文介绍了iOS:如何在没有fps下降的情况下播放音频?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Sprite Kit(最好是使用Swift库)为iOS 9+开发游戏.

I am in the process of developing a game for iOS 9+ using Sprite Kit and preferably using Swift libraries.

当前,我正在使用Singleton来预加载音频文件,每个音频文件都连接到AVAudioPlayer的单独实例.

Currently I'm using a Singleton where I preload my audio files, each connected to a separate instance of AVAudioPlayer.

这里有一个简短的代码片段可以理解这个想法:

Here's a short code-snipped to get the idea:

import SpriteKit
import AudioToolbox
import AVFoundation

class AudioEngine {

    static let sharedInstance = AudioEngine()

    internal var sfxPing: AVAudioPlayer

    private init() {

        self.sfxPing = AVAudioPlayer()

        if let path = NSBundle.mainBundle().pathForResource("ping", ofType: "m4a") {
            do {
                let url = NSURL(fileURLWithPath:path)
                sfxPing = try AVAudioPlayer(contentsOfURL: url)
                sfxPing.prepareToPlay()
            } catch {
                print("ERROR: Can't load ping.m4a audio file.")
            }
        }

    }

}

此Singleton在应用程序启动期间初始化.然后,在游戏循环中,我只需调用以下行来播放特定的音频文件:

This Singleton is initialised during app start-up. In the game-loop I then just call the following line to play a specific audio file:

AudioEngine.sharedInstance.sfxPing.play()

这基本上可以正常工作,但是在播放文件并且iPad Air上的帧频从60.0降至56.0时,我总是会出现小故障.

有人知道如何使用AVAudioPlayer解决此性能问题吗?

Someone any idea how to fix this performance issue with AVAudioPlayer ?

我还注意第三方库,即:

I also watched out for 3rd party libraries, namely:

  • AudioKit [Looks very heavy-weighted]
  • ObjectAL [Last Update 2013 ...]
  • AVAudioEngine [Based on AVAudioPlayer, same problems ?]

要求:

  • 播放很多非常短的样本(例如镜头,命中等)
  • 播放一些电机效果(因此音调会很好)
  • 循环播放一些背景/环境声音
  • 没有令人讨厌的故障/帧频下降!

您是否可以根据我的要求推荐上述任何一个库或使用以上代码指出问题?

Could you recommend any of the above mentioned libraries for my requirements or point out the problems using the above code ?

更新:

通过以下方式播放短声音:

Playing short sounds with:

self.runAction(SKAction.playSoundFileNamed("sfx.caf", waitForCompletion: false))

确实可以提高帧速率. 我将具有Audiacity的音频文件导出为.caf格式(Apple的Core Audio格式).但是在本教程中,它们以"Signed 32-bit PCM"编码导出,在我的情况下导致音频播放受干扰.使用其他任何编码选项(32-bit floatU-LawA-Law等)对我来说都很好.

does indeed improve the frame rate. I exported the audio files with Audiacity to the .caf format (Apple's Core Audio Format). But in the tutorial, they export with "Signed 32-bit PCM" encoding which led to disturbed audio playback in my case. Using any of the other encoding options (32-bit float, U-Law, A-Law, etc..) worked fine for me.

为什么使用caf格式?与m4a之类的压缩格式相比,由于它是未压缩的,因此以较少的CPU开销将其更快地加载到内存中.对于在短时间间隔内播放很多的短音效,这是有道理的,并且对于占用几千字节的短音频文件,磁盘使用不会受到太大影响.对于较大的音频文件,例如环境和背景音乐,使用压缩格式(mp3m4a)显然是更好的选择.

Why using caf format? Because it's uncompressed and thus loaded faster into memory with less CPU overhead compared to compressed formats like m4a. For short sound effects played a lot in short intervals, this makes sense and disk usage is not affected much for short audio files consuming few kilobytes. For bigger audio files, like ambient and background music, using compressed formats (mp3, m4a) is obviously the better choice.

推荐答案

根据您的问题,如果您为iOS 9+开发游戏,则可以使用新的iOS 9库 SKAudioNode ( Apple官方文档):

According to your question, if you develop a game for iOS 9+, you can use the new iOS 9 library SKAudioNode (official Apple doc):

var backgroundMusic: SKAudioNode!

例如,您可以将其添加到didMoveToView():

For example you can add this to didMoveToView():

if let musicURL = NSBundle.mainBundle().URLForResource("music", withExtension: "m4a") {
    backgroundMusic = SKAudioNode(URL: musicURL)
    addChild(backgroundMusic)
}

您也可以使用它来播放简单的效果:

You can also use to play a simple effect:

let beep = SKAudioNode(fileNamed: "beep.wav")
beep.autoplayLooped = false
self.addChild(beep)

最后,如果要更改音量:

Finally, if you want to change the volume:

beep.runAction(SKAction.changeVolumeTo(0.4, duration: 0))

更新:

我看到您更新了有关AVAudioPlayerSKAction的问题.我已经对我的iOS8 +兼容游戏进行了测试.

I see you have update your question speaking about AVAudioPlayer and SKAction. I've tested both of them for my iOS8+ compatible games.

关于AVAudioPlayer,我个人使用由我自己制作的自定义库,该库基于旧的 SKTAudio .

About AVAudioPlayer, I personally use a custom library maked by me based from the old SKTAudio.

我看到了有关AVAudioPlayer init的代码,但是我的代码有所不同,因为我使用了:

I see your code, about AVAudioPlayer init, and my code is different because I use:

@available(iOS 7.0, *)
    public init(contentsOfURL url: NSURL, fileTypeHint utiString: String?)

我不知道fileTypeHint是否有所作为,所以请尝试让我了解您的测试.

I don't know if fileTypeHint make the difference, so try and fill me about your test.

有关代码的优势: 使用基于AVAudioPlayer的共享实例音频管理器,您可以控制音量,在任何需要的地方使用管理器,确保与iOS8兼容

Advantages about your code: With a shared instance audio manager based to AVAudioPlayer you can control volume, use your manager wherever you want, ensure compatibility with iOS8

关于代码的缺点: 每当您播放声音并想要播放其他声音时,前一个声音就会中断,尤其是当您启动背景音乐时.

Disadvantages about your code: Everytime you play a sound and you want to play another sound, the previous is broken, especially if you have launch a background music.

如何解决?根据此SO,发布即可正常工作而不会出现问题似乎AVFoundation限于4个AVAudioPlayer属性实例化,因此您可以执行以下操作:

How to solve? According with this SO post to work well without issues seems AVFoundation is limited to 4 AVAudioPlayer properties instantiables, so you can do this:

  • 1)backgroundMusicPlayer:AVAudioPlayer!
  • 2)soundEffectPlayer1:AVAudioPlayer!
  • 3)soundEffectPlayer2:AVAudioPlayer!
  • 4)soundEffectPlayer3:AVAudioPlayer!

您可以构建一个方法来切换3个soundEffect以查看是否被占用:

You could build a method that switch through the 3 soundEffect to see if is occupied:

if player.playing

并使用下一个免费播放器.通过这种解决方法,您始终可以正确播放声音,甚至可以播放背景音乐.

and use the next free player. With this workaround you have always your sound played correctly, even your background music.

这篇关于iOS:如何在没有fps下降的情况下播放音频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆