Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/108.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS Swift中简单的低延迟音频播放_Ios_Swift_Audio_Avaudioplayer_Low Latency - Fatal编程技术网

iOS Swift中简单的低延迟音频播放

iOS Swift中简单的低延迟音频播放,ios,swift,audio,avaudioplayer,low-latency,Ios,Swift,Audio,Avaudioplayer,Low Latency,我是iOS的初学者,我正在尝试用Swift设计一个鼓集应用程序。我设计了一个带有单个按钮的视图,并编写了以下代码,但它存在一些问题: 当我像击鼓一样快速按下按钮时,有些声音消失了 仍然是在“鼓声”中,每次触摸按钮时声音都会中断,而不是让样本播放到结束。举个例子,钹的声音很糟糕。我想听到每一个样本的声音完全,即使我再按一下按钮 触摸和声音之间存在延迟。我知道AVAudioPlayer不是低延迟音频的最佳选择,但作为初学者,如果没有Swift中的代码示例或教程,很难学习OpenAL,AudioUni

我是iOS的初学者,我正在尝试用Swift设计一个鼓集应用程序。我设计了一个带有单个按钮的视图,并编写了以下代码,但它存在一些问题:

  • 当我像击鼓一样快速按下按钮时,有些声音消失了
  • 仍然是在“鼓声”中,每次触摸按钮时声音都会中断,而不是让样本播放到结束。举个例子,钹的声音很糟糕。我想听到每一个样本的声音完全,即使我再按一下按钮
  • 触摸和声音之间存在延迟。我知道
    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中,苹果提供了