iOS Swift中简单的低延迟音频播放
我是iOS的初学者,我正在尝试用Swift设计一个鼓集应用程序。我设计了一个带有单个按钮的视图,并编写了以下代码,但它存在一些问题:iOS Swift中简单的低延迟音频播放,ios,swift,audio,avaudioplayer,low-latency,Ios,Swift,Audio,Avaudioplayer,Low Latency,我是iOS的初学者,我正在尝试用Swift设计一个鼓集应用程序。我设计了一个带有单个按钮的视图,并编写了以下代码,但它存在一些问题: 当我像击鼓一样快速按下按钮时,有些声音消失了 仍然是在“鼓声”中,每次触摸按钮时声音都会中断,而不是让样本播放到结束。举个例子,钹的声音很糟糕。我想听到每一个样本的声音完全,即使我再按一下按钮 触摸和声音之间存在延迟。我知道AVAudioPlayer不是低延迟音频的最佳选择,但作为初学者,如果没有Swift中的代码示例或教程,很难学习OpenAL,AudioUni
AVAudioPlayer
不是低延迟音频的最佳选择,但作为初学者,如果没有Swift
中的代码示例或教程,很难学习OpenAL
,AudioUnit
。问题与此类似:override func viewDidLoad() {
super.viewDidLoad()
// Enable multiple touch for the button
for v in view.subviews {
if v.isKindOfClass(UIButton) {
v.multipleTouchEnabled = true
}
}
// Init audio
audioURL = NSBundle.mainBundle().URLForResource("snareDrum", withExtension: "wav")!
do {
player = try AVAudioPlayer(contentsOfURL: audioURL)
player?.prepareToPlay()
} catch {
print("AVAudioPlayer Error")
}
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
player?.stop()
player = nil
}
@IBAction func playSound(sender: UIButton) {
player?.currentTime = 0
player?.play()
}
如果您需要极低的延迟,我发现AVAudioSession singleton上有一个非常简单的解决方案(当应用程序启动时会自动实例化): 首先,使用以下类方法获取对应用程序AVAudioSession singleton的引用: (来自: 获取共享音频会话 迅速申报
class func sharedInstance()->AVAudioSession
然后,尝试将首选IO缓冲区持续时间设置为非常长的时间
使用此实例方法的short(例如.002):
设置首选音频I/O缓冲区持续时间(秒)
迅速申报
func setPreferredIOBufferDuration(\uduration:NSTimeInterval)抛出
参数
duration
所需的音频I/O缓冲区持续时间(以秒为单位)
使用
outError
在输入时,指向错误对象的指针。如果有错误
发生时,指针被设置为描述
错误。如果不需要错误信息,请传入nil。返回值
如果请求成功,则为true,否则为false
讨论
此方法请求更改I/O缓冲区持续时间。断定
无论更改是否生效,请使用IOBufferDuration属性。
有关详细信息,请参阅
请记住上面的注意事项-IOBufferDuration
属性是否实际设置为传递给func setPreferedioBufferDuration(uDuration:NSTimeInterval)throws
方法的值,取决于函数是否返回错误,以及我不完全清楚的其他因素。此外,在我的测试中,我发现如果将此值设置为极低的值,确实会设置该值(或接近该值的值),但在播放文件(例如使用AVAudioPlayerNode)时,不会播放声音。没有错误,只是没有声音。这显然是个问题。我还没有发现如何测试这个问题,除非在实际设备上测试时注意到耳朵没有声音。我会调查的。但现在,我建议将首选持续时间设置为不小于.002或.0015。0.0015的值似乎适用于我正在测试的iPad Air(A1474型)。而低至.0012似乎在我的iPhone6S上运行良好
从CPU开销的角度考虑的另一件事是音频文件的格式。未压缩格式在播放时的CPU开销非常低。苹果公司建议,为了获得最高的质量和最低的开销,您应该使用CAF文件。对于压缩文件和最低开销,应使用IMA4压缩:
(来自:
iOS中用于未压缩(最高质量)的首选音频格式
音频,使用16位,小端,线性PCM音频数据打包在
CAF文件。您可以在Mac OS X中将音频文件转换为这种格式
使用afconvert命令行工具,如下所示:
/usr/bin/afconvert-f caff-d LEI16{INPUT}{OUTPUT}
在需要播放多个声音时减少内存使用
同时,使用IMA4(IMA/ADPCM)压缩。这减少了文件的数量
大小,但在解压缩过程中对CPU的影响最小。如同
线性PCM数据,将IMA4数据打包在CAF文件中
您也可以使用afconvert转换为IMA4:
/usr/bin/afconvert-f AIFC-d ima4[文件]
我花了一个下午的时间尝试通过玩AVAudioPlayer和AVAudioSession来解决这个问题,但我无法使用它。(不幸的是,按照此处接受的答案所建议的设置IO缓冲区持续时间似乎没有帮助。)我也尝试了AudioToolbox,但我发现产生的性能几乎相同-相关用户操作和音频之间明显存在延迟
在浏览了一下互联网后,我发现:
www.rockhoppertech.com/blog/swift-avfoundation/
关于AVAudioEngine的部分非常有用。以下代码是轻微的返工:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var engine = AVAudioEngine()
var playerNode = AVAudioPlayerNode()
var mixerNode: AVAudioMixerNode?
var audioFile: AVAudioFile?
@IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
engine.attach(playerNode)
mixerNode = engine.mainMixerNode
engine.connect(playerNode, to: mixerNode!, format: mixerNode!.outputFormat(forBus: 0))
do {
try engine.start()
}
catch let error {
print("Error starting engine: \(error.localizedDescription)")
}
let url = Bundle.main.url(forResource: "click_04", withExtension: ".wav")
do {
try audioFile = AVAudioFile(forReading: url!)
}
catch let error {
print("Error opening audio file: \(error.localizedDescription)")
}
}
@IBAction func playSound(_ sender: Any) {
engine.connect(playerNode, to: engine.mainMixerNode, format: audioFile?.processingFormat)
playerNode.scheduleFile(audioFile!, at: nil, completionHandler: nil)
if engine.isRunning{
playerNode.play()
} else {
print ("engine not running")
}
}
}
这可能并不完美,因为我是一个敏捷的新手,以前从未使用过AVAudioEngine。不过,它似乎确实起作用了 我认为音频单元可能是获得你想要的那种低延迟行为的唯一途径,尽管如果有人告诉我我错了,我会很高兴。我正在学习如何在Swift中使用AudioToolbox,并很高兴与大家分享我所学的内容。感谢您的回复,我将感谢您在Swift中使用AudioToolbox提供的帮助。我们怎么联系?通过电子邮件?你收到我的电子邮件地址了吗?我把它放在这里大约30分钟,然后把它删除了…对不起,我没弄明白。你介意给我发电子邮件吗?可以在我的网站上找到:(在页脚)。我不确定StackOverflow是否可以在这里发布。我同意@RomanSausarnes的观点-您没有足够的时间控制AVAudioPlayer
,无法在此应用程序中使用。好消息是,在iOS7中,苹果提供了