将AVAudioSourceNode连接到AVAudioSinkNode不起作用(示例代码)

栏目: ios · 发布时间: 2021-05-07

简介  这篇文章主要介绍了将AVAudioSourceNode连接到AVAudioSinkNode不起作用(示例代码)以及相关的经验技巧,文章约4898字,浏览量354,点赞数6,值得推荐!

上下文

我正在使用AVAudioEngine编写信号解释器,它将分析麦克风输入。在开发过程中,我想使用默认的输入缓冲区,因此不必让麦克风发出噪音来测试我的更改。我正在使用Catalyst开发。

问题

我正在使用AVAudioSinkNode来获取声音缓冲区(据称其性能比使用.installTap更好)。我正在使用AVAudioSourceNode的子类来生成正弦波。当我将这两个连接在一起时,我希望接收器节点的回调被调用,但事实并非如此。源节点的渲染块均未调用。

let engine = AVAudioEngine()

let output = engine.outputNode
let outputFormat = output.inputFormat(forBus: 0)
let sampleRate = Float(outputFormat.sampleRate)

let sineNode440 = AVSineWaveSourceNode(
    frequency: 440,
    amplitude: 1,
    sampleRate: sampleRate
)

let sink = AVAudioSinkNode { _, frameCount, audioBufferList -> OSStatus in
    print("[SINK] + (frameCount) (Date().timeIntervalSince1970)")
    return noErr
}

engine.attach(sineNode440)
engine.attach(sink)
engine.connect(sineNode440, to: sink, format: nil)

try engine.start()

附加测试

如果我将engine.inputNode连接到接收器(即engine.connect(engine.inputNode, to: sink, format: nil)),则按预期方式调用接收器回调。

[将sineNode440连接到engine.outputNode时,我可以听到声音并且按预期方式调用了渲染块。因此,当连接到设备输入/输出时,源和接收器都可以单独工作,但不能一起工作。

AVSineWaveSourceNode

对该问题不重要,但相关:AVSineWaveSourceNode基于Apple sample code。连接到engine.outputNode时,此节点会发出正确的声音。

class AVSineWaveSourceNode: AVAudioSourceNode {

    /// We need this separate class to be able to inject the state in the render block.
    class State {
        let amplitude: Float
        let phaseIncrement: Float
        var phase: Float = 0

        init(frequency: Float, amplitude: Float, sampleRate: Float) {
            self.amplitude = amplitude
            phaseIncrement = (2 * .pi / sampleRate) * frequency
        }
    }

    let state: State

    init(frequency: Float, amplitude: Float, sampleRate: Float) {
        let state = State(
            frequency: frequency,
            amplitude: amplitude,
            sampleRate: sampleRate
        )
        self.state = state

        let format = AVAudioFormat(standardFormatWithSampleRate: Double(sampleRate), channels: 1)!

        super.init(format: format, renderBlock: { isSilence, _, frameCount, audioBufferList -> OSStatus in
            print("[SINE GENERATION (frequency) - (frameCount)]")
            let tau = 2 * Float.pi
            let ablPointer = UnsafeMutableAudioBufferListPointer(audioBufferList)
            for frame in 0..<Int(frameCount) {
                // Get signal value for this frame at time.
                let value = sin(state.phase) * amplitude
                // Advance the phase for the next frame.
                state.phase += state.phaseIncrement
                if state.phase >= tau {
                    state.phase -= tau
                }
                if state.phase < 0.0 {
                    state.phase += tau
                }
                // Set the same value on all channels (due to the inputFormat we have only 1 channel though).
                for buffer in ablPointer {
                    let buf: UnsafeMutableBufferPointer<Float> = UnsafeMutableBufferPointer(buffer)
                    buf[frame] = value
                }
            }

            return noErr
        })

        for i in 0..<self.numberOfInputs {
            print("[SINEWAVE (frequency)] BUS (i) input format: (self.inputFormat(forBus: i))")
        }

        for i in 0..<self.numberOfOutputs {
            print("[SINEWAVE (frequency)] BUS (i) output format: (self.outputFormat(forBus: i))")
        }
    }
}
答案

outputNode会在正常配置AVAudioEngine(“在线”)时驱动音频处理图。 outputNode从其输入节点提取音频,从其输入节点提取音频,等等。当您将sineNodesink彼此连接而未连接到outputNode时,则没有任何内容sink的输出总线或outputNode的输入总线,因此,当硬件从outputNode请求音频时,它无处可获取。

[如果我理解正确,我认为您可以通过摆脱sink,将sineNode连接到outputNode,并在AVAudioEngine中运行manual rendering mode来完成您想要的工作。在手动渲染模式下,您传递一个手动渲染块以接收音频(类似于AVAudioSinkNode),并通过调用renderOffline(_:to:)手动驱动图形。


以上就是本文的全部内容,希望对大家的学习有所帮助,本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

Swift ios将多个项目连接到同一个IBOutlet(示例代码)

无法将StormCrawler连接到安全的Elasticsearch

如何将TCP连接重新连接到同一端口?

关于将数据连接到云上(示例代码)

黑莓手机将无法连接到一些HTTPS的网页。

如何将MySQL服务器连接到工作台(示例代码)

使用?wsdl URI查询将LinqPad连接到WCF Web服务

如何将Django ORM连接到mongo atlas?