ios - 使用 AVAudioEngine 离线渲染音频文件

标签 ios swift avfoundation avaudioplayer avaudioengine

我想录制音频文件并通过应用一些效果来保存它。 录音还可以,用效果播放这段音频也可以。 问题是当我尝试离线保存此类音频时,它会生成空音频文件。 这是我的代码:

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 来刷新 header 并关闭 m4a 文件。

关于ios - 使用 AVAudioEngine 离线渲染音频文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52184148/

相关文章:

ios - "Tap to focus"到 "auto focus"当相机 View 中的内容发生变化时。像股票相机应用程序或 iOS 的 UIImagePickerController 中的逻辑?

ios - 找不到有关 forTraitCollection 的苹果文档

ios - 我无法发送推送通知来测试 Flight Expo 独立应用程序

ios - 防止 initWithContentsOfURL : from using cache

ios - 新的 iOS 10 Today Widget/Extension 的高度是多少?

ios - 如何从图像创建 AVAsset

swift - 使用 Swift 从视频中抓取帧

IOS Iphone 3G 的 Javascript API 用于相机访问

swift - 在 MacOS 应用程序中设置 Realm 架构版本

Swift 调用中的额外参数