将AVAudioSourceNode连接到AVAudioSinkNode不起作用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将AVAudioSourceNode连接到AVAudioSinkNode不起作用相关的知识,希望对你有一定的参考价值。
上下文
我正在使用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
从其输入节点提取音频,从其输入节点提取音频,等等。当您将sineNode
和sink
彼此连接而未连接到outputNode
时,则没有任何内容sink
的输出总线或outputNode
的输入总线,因此,当硬件从outputNode
请求音频时,它无处可获取。
[如果我理解正确,我认为您可以通过摆脱sink
,将sineNode
连接到outputNode
,并在AVAudioEngine
中运行manual rendering mode来完成您想要的工作。在手动渲染模式下,您传递一个手动渲染块以接收音频(类似于AVAudioSinkNode
),并通过调用renderOffline(_:to:)手动驱动图形。
以上是关于将AVAudioSourceNode连接到AVAudioSinkNode不起作用的主要内容,如果未能解决你的问题,请参考以下文章
我无法将 TableViewCell 按钮连接到 TableViewController!如何将 TableViewCell 中的值连接到 TableViewController?
“无法连接到远程 VM”将 jdb 连接到 Windows 上的 android 模拟器
将 Auth0 连接到我的后端后,如何将其连接到我的 NextJS 前端?
将 nesjs 应用程序连接到 SQL Server Express 时出错:无法连接到 localhost:1433 - 自签名证书