Ios 在Swift中使用AVAudioEngine轻触麦克风输入
我对新的AVAudioEngine非常兴奋。它似乎是围绕音频单元的一个很好的API包装器。不幸的是,文档到目前为止还不存在,我在使用一个简单的图表时遇到了问题 使用以下简单代码设置音频引擎图,将永远不会调用tap块。它模仿了一些在web上浮动的示例代码,尽管这些代码也不起作用Ios 在Swift中使用AVAudioEngine轻触麦克风输入,ios,swift,avfoundation,core-audio,ios8.1,Ios,Swift,Avfoundation,Core Audio,Ios8.1,我对新的AVAudioEngine非常兴奋。它似乎是围绕音频单元的一个很好的API包装器。不幸的是,文档到目前为止还不存在,我在使用一个简单的图表时遇到了问题 使用以下简单代码设置音频引擎图,将永远不会调用tap块。它模仿了一些在web上浮动的示例代码,尽管这些代码也不起作用 let inputNode = audioEngine.inputNode var error: NSError? let bus = 0 inputNode.installTapOnBus(bus, buffe
let inputNode = audioEngine.inputNode
var error: NSError?
let bus = 0
inputNode.installTapOnBus(bus, bufferSize: 2048, format: inputNode.inputFormatForBus(bus)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
println("sfdljk")
}
audioEngine.prepare()
if audioEngine.startAndReturnError(&error) {
println("started audio")
} else {
if let engineStartError = error {
println("error starting audio: \(engineStartError.localizedDescription)")
}
}
class AudioProcessor {
let audioEngine = AVAudioEngine()
init(){
let inputNode = audioEngine.inputNode
let bus = 0
var error: NSError?
inputNode.installTapOnBus(bus, bufferSize: 2048, format:inputNode.inputFormatForBus(bus)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
println("sfdljk")
}
audioEngine.prepare()
audioEngine.startAndReturnError(nil)
println("started audio")
}
}
我要找的是原始pcm缓冲区,用于分析。我不需要任何效果或输出。根据WWDC讲座“502音频引擎在实践中”,此设置应该可以工作
现在,如果您想从输入节点捕获数据,您可以安装一个节点点击,我们已经讨论过了
但这个特殊示例的有趣之处在于,如果我只想使用输入节点,比如说从麦克风中捕获数据,并可能对其进行检查、实时分析或将其写入文件,我可以直接在输入节点上安装一个点击
轻触将完成拉入输入节点以获取数据的工作,将其填充到缓冲区中,然后将其返回给应用程序
一旦你有了这些数据,你就可以用它做任何你需要做的事情
以下是我尝试过的一些链接:
let inputNode = audioEngine.inputNode
var error: NSError?
let bus = 0
inputNode.installTapOnBus(bus, bufferSize: 2048, format: inputNode.inputFormatForBus(bus)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
println("sfdljk")
}
audioEngine.prepare()
if audioEngine.startAndReturnError(&error) {
println("started audio")
} else {
if let engineStartError = error {
println("error starting audio: \(engineStartError.localizedDescription)")
}
}
class AudioProcessor {
let audioEngine = AVAudioEngine()
init(){
let inputNode = audioEngine.inputNode
let bus = 0
var error: NSError?
inputNode.installTapOnBus(bus, bufferSize: 2048, format:inputNode.inputFormatForBus(bus)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
println("sfdljk")
}
audioEngine.prepare()
audioEngine.startAndReturnError(nil)
println("started audio")
}
}
可能的情况是,您的AVAudioEngine超出了范围,由ARC发布(“如果您喜欢它,那么您应该将retain放在它上面…”) 以下代码(发动机移动到ivar并因此粘住)触发水龙头:
class AppDelegate: NSObject, NSApplicationDelegate {
let audioEngine = AVAudioEngine()
func applicationDidFinishLaunching(aNotification: NSNotification) {
let inputNode = audioEngine.inputNode
let bus = 0
inputNode.installTapOnBus(bus, bufferSize: 2048, format: inputNode.inputFormatForBus(bus)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
println("sfdljk")
}
audioEngine.prepare()
audioEngine.startAndReturnError(nil)
}
}
(为了简洁起见,我删除了错误处理)上面的答案对我不起作用,但下面的答案确实起作用。我正在混音器节点上安装一个水龙头
mMixerNode?.installTapOnBus(0, bufferSize: 4096, format: mMixerNode?.outputFormatForBus(0),
{
(buffer: AVAudioPCMBuffer!, time:AVAudioTime!) -> Void in
NSLog("tapped")
}
)
更新:我实现了一个完整的录制麦克风输入的工作示例,在运行时应用一些效果(混响、延迟、失真),并将所有这些效果保存到输出文件中
var engine = AVAudioEngine()
var distortion = AVAudioUnitDistortion()
var reverb = AVAudioUnitReverb()
var audioBuffer = AVAudioPCMBuffer()
var outputFile = AVAudioFile()
var delay = AVAudioUnitDelay()
//初始化音频引擎
func initializeAudioEngine() {
engine.stop()
engine.reset()
engine = AVAudioEngine()
isRealTime = true
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
let ioBufferDuration = 128.0 / 44100.0
try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(ioBufferDuration)
} catch {
assertionFailure("AVAudioSession setup error: \(error)")
}
let fileUrl = URLFor("/NewRecording.caf")
print(fileUrl)
do {
try outputFile = AVAudioFile(forWriting: fileUrl!, settings: engine.mainMixerNode.outputFormatForBus(0).settings)
}
catch {
}
let input = engine.inputNode!
let format = input.inputFormatForBus(0)
//settings for reverb
reverb.loadFactoryPreset(.MediumChamber)
reverb.wetDryMix = 40 //0-100 range
engine.attachNode(reverb)
delay.delayTime = 0.2 // 0-2 range
engine.attachNode(delay)
//settings for distortion
distortion.loadFactoryPreset(.DrumsBitBrush)
distortion.wetDryMix = 20 //0-100 range
engine.attachNode(distortion)
engine.connect(input, to: reverb, format: format)
engine.connect(reverb, to: distortion, format: format)
engine.connect(distortion, to: delay, format: format)
engine.connect(delay, to: engine.mainMixerNode, format: format)
assert(engine.inputNode != nil)
isReverbOn = false
try! engine.start()
}
//现在,录制功能:
func startRecording() {
let mixer = engine.mainMixerNode
let format = mixer.outputFormatForBus(0)
mixer.installTapOnBus(0, bufferSize: 1024, format: format, block:
{ (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
print(NSString(string: "writing"))
do{
try self.outputFile.writeFromBuffer(buffer)
}
catch {
print(NSString(string: "Write failed"));
}
})
}
func stopRecording() {
engine.mainMixerNode.removeTapOnBus(0)
engine.stop()
}
我希望这对你有帮助。谢谢 好话题
嗨,布罗德尼
在你的主题中,我找到了我的解决方案。这里有类似的话题
参见Wwdc 2014 502-AVAudioEngine在实践中的讲座在20分钟内捕获麦克风=>在21.50中使用tap代码创建缓冲区=>
这是swift 3代码
@IBAction func button01Pressed(_ sender: Any) {
let inputNode = audioEngine.inputNode
let bus = 0
inputNode?.installTap(onBus: bus, bufferSize: 2048, format: inputNode?.inputFormat(forBus: bus)) {
(buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
var theLength = Int(buffer.frameLength)
print("theLength = \(theLength)")
var samplesAsDoubles:[Double] = []
for i in 0 ..< Int(buffer.frameLength)
{
var theSample = Double((buffer.floatChannelData?.pointee[i])!)
samplesAsDoubles.append( theSample )
}
print("samplesAsDoubles.count = \(samplesAsDoubles.count)")
}
audioEngine.prepare()
try! audioEngine.start()
}
我尝试了这一点,并用使用的代码编辑了我的问题。你答案中的密码对你有用吗?朱普,对我有用。我还没有在操场上测试过它,但在从Xcode编译运行时它可以工作。水龙头被连续不断地调用。遗憾的是,我不得不承认它毕竟是一个未修复的对象。我的AudioProcessor类是在一个方法中实例化的,而不是作为类属性实例化的。您为什么选择带有“notification”参数的appDelegate方法?默认/事实上的选项是didFinishLaunchingWithOptions:原因是在我编写答案时(2014年),Xcode会将通知参数作为默认参数提供给我。对于手头的问题,这并不重要。这是可行的,但是有没有一种方法可以让它工作,而不让演讲者实时产生效果?@user3344977我目前正在处理一个类似的模块,我还没有成功地实现它。i、 e.带效果的音频文件的脱机渲染。以下是我关注的帖子:[离线渲染]()。希望它有帮助这些值来自哪里?:让ioBufferDuration=128.0/44100.0有用的代码运行。现在我有了关于这个AudioEngine如何在AudioUnits之间的所有连接中工作的代码。它工作得很好。但是,如果添加AVAudioUnitTimePitch节点,它会崩溃:(我也提出了类似的解决方案。事情只会运行一次,然后在5分钟内不会再次运行。当你的应用程序即将终止时,你需要移除轻触并停止音频引擎(我在调试器中执行此操作)。我还将AudioSession设置为非活动状态