我是iOS的初学者,我正在尝试用Swift设计一个鼓组应用程序.我用一个按钮设计了一个视图并编写了下面的代码,但它有一些问题:
当我像滚筒一样快速触摸按钮时,有些声音会丢失.
仍处于"鼓声"中,每次触摸按钮时声音都会中断,而不是让样本播放直到结束.例如,钹卷很糟糕.即使我再次触摸按钮,我也希望听到每个样本完全响起.
触摸和声音之间存在延迟.我知道这AVAudioPlayer
是不是低延迟音频的最佳选择,但作为一个初学者,它很难学OpenAL
,AudioUnit
没有代码示例或教程Swift
.问题与此类似:我应该使用哪种框架在iOS中播放低延迟的音频文件(WAV,MP3,AIFF)?.
代码:
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() }
小智.. 6
如果您需要极低的延迟,我发现AVAudioSession单例上有一个非常简单的解决方案(在应用程序启动时会自动实例化):
首先,使用此类方法获取对应用程序的AVAudioSession单例的引用:
(来自AVAudioSession类参考):
获得共享音频会话
声明SWIFT
class func sharedInstance() -> AVAudioSession
然后,尝试使用此实例方法将首选IO缓冲区持续时间设置为非常短的(例如.002):
设置首选音频I/O缓冲持续时间,以秒为单位.
声明SWIFT
func setPreferredIOBufferDuration(_ duration: NSTimeInterval) throws
参数
duration
要使用的音频I/O缓冲持续时间(以秒为单位).
outError
在输入时,指向错误对象的指针.如果发生错误,则将指针设置为描述错误的NSError对象.如果您不想要错误信息,请传入零.返回值如果请求成功,则返回true,否则返回false.讨论
此方法请求更改I/O缓冲区持续时间.要确定更改是否生效,请使用IOBufferDuration属性.详情请参见配置音频会话.
请记住上面的注释 - IOBufferDuration
属性是否实际设置为传递给func setPrefferedIOBufferDuration(_ duration: NSTimeInterval) throws
方法的值,取决于不返回错误的函数,以及我不完全清楚的其他因素.另外 - 在我的测试中 - 我发现如果你将这个值设置为一个非常低的值,那么值(或接近它的值)确实会被设置,但是当播放文件时(例如使用AVAudioPlayerNode)声音不会玩了.没有错误,只是没有声音.这显然是个问题.我还没有发现如何测试这个问题,除非注意到在实际设备上测试时听不到声音.我会调查一下.但就目前而言,我建议将首选持续时间设置为不小于.002或.0015..0015的值似乎适用于我正在测试的iPad Air(型号A1474).虽然低至.0012似乎在我的iPhone 6S上运行良好.
从CPU开销角度考虑的另一件事是音频文件的格式.未压缩格式在播放时将具有非常低的CPU开销.Apple建议您使用CAF文件以获得最高质量和最低开销.对于压缩文件和最低开销,您应该使用IMA4压缩:
(来自iOS多媒体编程指南):
iOS中的首选音频格式对于未压缩(最高质量)音频,请使用打包在CAF文件中的16位小端线性PCM音频数据.您可以使用afconvert命令行工具在Mac OS X中将音频文件转换为此格式,如下所示:
/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}
当您需要同时播放多个声音时,为了减少内存使用量,请使用IMA4(IMA/ADPCM)压缩.这样可以减小文件大小,但在解压缩过程中对CPU的影响最小.与线性PCM数据一样,在CAF文件中打包IMA4数据.
您也可以使用afconvert转换为IMA4:
/usr/bin/afconvert -f AIFC -d ima4 [file]
如果您需要极低的延迟,我发现AVAudioSession单例上有一个非常简单的解决方案(在应用程序启动时会自动实例化):
首先,使用此类方法获取对应用程序的AVAudioSession单例的引用:
(来自AVAudioSession类参考):
获得共享音频会话
声明SWIFT
class func sharedInstance() -> AVAudioSession
然后,尝试使用此实例方法将首选IO缓冲区持续时间设置为非常短的(例如.002):
设置首选音频I/O缓冲持续时间,以秒为单位.
声明SWIFT
func setPreferredIOBufferDuration(_ duration: NSTimeInterval) throws
参数
duration
要使用的音频I/O缓冲持续时间(以秒为单位).
outError
在输入时,指向错误对象的指针.如果发生错误,则将指针设置为描述错误的NSError对象.如果您不想要错误信息,请传入零.返回值如果请求成功,则返回true,否则返回false.讨论
此方法请求更改I/O缓冲区持续时间.要确定更改是否生效,请使用IOBufferDuration属性.详情请参见配置音频会话.
请记住上面的注释 - IOBufferDuration
属性是否实际设置为传递给func setPrefferedIOBufferDuration(_ duration: NSTimeInterval) throws
方法的值,取决于不返回错误的函数,以及我不完全清楚的其他因素.另外 - 在我的测试中 - 我发现如果你将这个值设置为一个非常低的值,那么值(或接近它的值)确实会被设置,但是当播放文件时(例如使用AVAudioPlayerNode)声音不会玩了.没有错误,只是没有声音.这显然是个问题.我还没有发现如何测试这个问题,除非注意到在实际设备上测试时听不到声音.我会调查一下.但就目前而言,我建议将首选持续时间设置为不小于.002或.0015..0015的值似乎适用于我正在测试的iPad Air(型号A1474).虽然低至.0012似乎在我的iPhone 6S上运行良好.
从CPU开销角度考虑的另一件事是音频文件的格式.未压缩格式在播放时将具有非常低的CPU开销.Apple建议您使用CAF文件以获得最高质量和最低开销.对于压缩文件和最低开销,您应该使用IMA4压缩:
(来自iOS多媒体编程指南):
iOS中的首选音频格式对于未压缩(最高质量)音频,请使用打包在CAF文件中的16位小端线性PCM音频数据.您可以使用afconvert命令行工具在Mac OS X中将音频文件转换为此格式,如下所示:
/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}
当您需要同时播放多个声音时,为了减少内存使用量,请使用IMA4(IMA/ADPCM)压缩.这样可以减小文件大小,但在解压缩过程中对CPU的影响最小.与线性PCM数据一样,在CAF文件中打包IMA4数据.
您也可以使用afconvert转换为IMA4:
/usr/bin/afconvert -f AIFC -d ima4 [file]