使用 AVAudioEngine 离线渲染音频文件
Posted
技术标签:
【中文标题】使用 AVAudioEngine 离线渲染音频文件【英文标题】:Render audio file offline using AVAudioEngine 【发布时间】:2018-09-05 11:33:40 【问题描述】:我想录制音频文件并通过应用一些效果来保存它。 录音没问题,播放这个有效果的音频也没问题。 问题是当我尝试离线保存此类音频时,它会产生空音频文件。 这是我的代码:
let effect = AVAudioUnitTimePitch()
effect.pitch = -300
self.addSomeEffect(effect)
func addSomeEffect(_ effect: AVAudioUnit)
try? AVAudiosession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
let format = self.audioFile.processingFormat
self.audioEngine.stop()
self.audioEngine.reset()
self.audioEngine = AVAudioEngine()
let audioPlayerNode = AVAudioPlayerNode()
self.audioEngine.attach(audioPlayerNode)
self.audioEngine.attach(effect)
self.audioEngine.connect(audioPlayerNode, to: self.audioEngine.mainMixerNode, format: format)
self.audioEngine.connect(effect, to: self.audioEngine.mainMixerNode, format: format)
audioPlayerNode.scheduleFile(self.audioFile, at: nil)
do
let maxNumberOfFrames: AVAudioFrameCount = 8096
try self.audioEngine.enableManualRenderingMode(.offline,
format: format,
maximumFrameCount: maxNumberOfFrames)
catch
fatalError()
do
try audioEngine.start()
audioPlayerNode.play()
catch
let outputFile: AVAudioFile
do
let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("temp.m4a")
if FileManager.default.fileExists(atPath: url.path)
try? FileManager.default.removeItem(at: url)
let recordSettings = self.audioFile.fileFormat.settings
outputFile = try AVAudioFile(forWriting: url, settings: recordSettings)
catch
fatalError()
let buffer = AVAudioPCMBuffer(pcmFormat: self.audioEngine.manualRenderingFormat,
frameCapacity: self.audioEngine.manualRenderingMaximumFrameCount)!
while self.audioEngine.manualRenderingSampleTime < self.audioFile.length
do
let framesToRender = min(buffer.frameCapacity,
AVAudioFrameCount(self.audioFile.length - self.audioEngine.manualRenderingSampleTime))
let status = try self.audioEngine.renderOffline(framesToRender, to: buffer)
switch status
case .success:
print("Write to file")
try outputFile.write(from: buffer)
case .error:
fatalError()
default:
break
catch
fatalError()
print("Finish write")
audioPlayerNode.stop()
audioEngine.stop()
self.outputFile = outputFile
self.audioPlayer = try? AVAudioPlayer(contentsOf: outputFile.url)
AVAudioPlayer 无法打开带有输出 url 的文件。我通过文件系统查看了文件,是空的,无法播放。
为 AVAudioSession 选择不同的类别也不起作用。
感谢您的帮助!
更新
我切换到在输出文件的记录中使用 .caf 文件扩展名,并且它有效。知道为什么 .m4a 不起作用吗?
【问题讨论】:
你需要 nil outputFile 来刷新头部并关闭 m4a 文件。 @RhythmicFistman 谢谢,它有效! 【参考方案1】:你需要nil
outputFile
刷新头部并关闭m4a文件。
【讨论】:
抱歉,为了清楚起见,您的意思是在所有内容完成渲染后的某个时间点将 outputFile 设置为 nil 吗? 没错。在你写完最后一个缓冲区之后,你通常会调用 close 你将AVAudioFile
设置为 nil。
顺便说一句,这在我的书中是一个非常愚蠢的 API 决定。使用对象清理的副作用来关闭文件既不容易发现,也不确定。我不明白为什么AVAudioFile
没有明确的close()
方法。以上是关于使用 AVAudioEngine 离线渲染音频文件的主要内容,如果未能解决你的问题,请参考以下文章