您的问题提到了音频单元和图表。正如评论中所说,图形概念已被将“节点”附加到 AVAudioEngine 的想法所取代。然后这些节点“连接”到其他节点。连接节点创建信号路径并启动引擎使这一切发生。这可能很明显,但我试图在这里做出一般性的回应。你可以在 Swift 或 Objective-C 中完成这一切。
iOS 音频需要考虑的两个高级观点是“主机”的概念和“插件”的概念。主机是一个应用程序,它托管插件。该插件通常被创建为“应用程序扩展”,您可以根据需要查找音频单元扩展以获取更多信息。你说你有一个做你想做的事,所以这都是解释主机中使用的代码
将 AudioUnit 附加到 AVaudioEngine
var components = [AVAudioUnitComponent]()
let description =
AudioComponentDescription(
componentType: 0,
componentSubType: 0,
componentManufacturer: 0,
componentFlags: 0,
componentFlagsMask: 0
)
components = AVAudioUnitComponentManager.shared().components(matching: description)
.compactMap({ au -> AVAudioUnitComponent? in
if AudioUnitTypes.codeInTypes(
au.audioComponentDescription.componentType,
AudioUnitTypes.instrumentAudioUnitTypes,
AudioUnitTypes.fxAudioUnitTypes,
AudioUnitTypes.midiAudioUnitTypes
) && !AudioUnitTypes.isApplePlugin(au.manufacturerName) {
return au
}
return nil
})
guard let component = components.first else { fatalError("bugs") }
let description = component.audioComponentDescription
AVAudioUnit.instantiate(with: description) { (audioUnit: AVAudioUnit?, error: Error?) in
if let e = error {
return print("\(e)")
}
// save and connect
guard let audioUnit = audioUnit else {
print("Audio Unit was Nil")
return
}
let hardwareFormat = self.engine.outputNode.outputFormat(forBus: 0)
self.engine.attach(au)
self.engine.connect(au, to: self.engine.mainMixerNode, format: hardwareFormat)
}
加载 AudioUnit 后,您可以连接下面的 Athe AVAudioNodeTapBlock,它还有更多功能,因为它需要是二进制文件或其他不属于您的主机应用程序可以加载的东西。
录制一个 AVAudioInputNode
(您可以用输入节点替换音频单元。)
在应用程序中,您可以通过创建 AVAudioInputNode 或仅引用 AVAudioEngine 的“inputNode”属性来录制音频,该属性将默认连接到系统选择的输入设备(麦克风、线路输入等)
拥有要处理其音频的输入节点后,接下来在该节点上“安装水龙头”。您还可以将输入节点连接到混音器节点并在那里安装分接头。
https://developer.apple.com/documentation/avfoundation/avaudionode/1387122-installtap
func installTap(onBus bus: AVAudioNodeBus,
bufferSize: AVAudioFrameCount,
format: AVAudioFormat?,
block tapBlock: @escaping AVAudioNodeTapBlock)
安装的分接头基本上会将您的音频流分成两个信号路径。它将继续将音频发送到 AvaudioEngine 的输出设备,并将音频发送到您定义的函数。此函数(AVAudioNodeTapBlock)从 AVAudioNode 传递给“installTap”。AVFoundation 子系统调用 AVAudioNodeTapBlock 并将输入数据一次传递一个缓冲区以及数据到达的时间。
https://developer.apple.com/documentation/avfoundation/avaudionodetapblock
typealias AVAudioNodeTapBlock = (AVAudioPCMBuffer, AVAudioTime) -> Void
现在系统正在将音频数据发送到可编程上下文,您可以使用它做任何您想做的事情。要在其他地方使用它,您可以创建一个单独的 AVAudioPCMBuffer 并将每个传入的缓冲区写入 AVAudioNodeTapBlock 中。