热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AudioKit4.3:录制音频,将其渲染为离线,然后播放

如何解决《AudioKit4.3:录制音频,将其渲染为离线,然后播放》经验,如何解决这个问题?

我正在尝试录制音频,然后离线保存AudioKit.renderToFile,然后AKPlayer用来播放原始录制的音频文件.

import UIKit
import AudioKit


class ViewController: UIViewController {

private var recordUrl:URL!
private var isRecording:Bool = false

public var player:AKPlayer!
private let format = AVAudioFormat(commonFormat: .pcmFormatFloat64, sampleRate: 44100, channels: 2, interleaved: true)!

private var amplitudeTracker:AKAmplitudeTracker!
private var boostedMic:AKBooster!
private var mic:AKMicrophone!
private var micMixer:AKMixer!
private var silence:AKBooster!
public var recorder: AKNodeRecorder!

@IBOutlet weak var recordButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()
    //self.recordUrl = Bundle.main.url(forResource: "sound", withExtension: "caf")
    //self.startAudioPlayback(url: self.recordUrl!)
    self.recordUrl = self.urlForDocument("record.caf")
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func requestMic(completion: @escaping () -> Void) {
    AVAudioSession.sharedInstance().requestRecordPermission({ (granted: Bool) in

        if granted { completion()}
    })
}
public func switchToMicrophone() {
    stopEngine()
    do {
        try AKSettings.setSession(category: .playAndRecord, with: .allowBluetoothA2DP)
    } catch {
        AKLog("Could not set session category.")
    }
    mic = AKMicrophone()
    micMixer = AKMixer(mic)
    boostedMic = AKBooster(micMixer, gain: 5)
    amplitudeTracker = AKAmplitudeTracker(boostedMic)
    silence = AKBooster(amplitudeTracker, gain: 0)
    AudioKit.output = silence
    startEngine()
}

@IBAction func startStopRecording(_ sender: Any) {
    self.isRecording = !self.isRecording

    if self.isRecording {
        self.startRecording()
        self.recordButton.setTitle("Stop Recording", for: .normal)
    } else {
        self.stopRecording()
        self.recordButton.setTitle("Start Recording", for: .normal)
    }
}

func startRecording() {
    self.requestMic() {
        self.switchToMicrophone()
        if let url = self.recordUrl {
            do {
            let audioFile = try AKAudioFile(forWriting: url, settings: self.format.settings, commonFormat: .pcmFormatFloat64, interleaved: true)

            self.recorder = try AKNodeRecorder(node: self.micMixer, file: audioFile)

            try self.recorder.reset()
            try self.recorder.record()
            } catch {
                print("error setting up recording", error)
            }
        }
    }
}

func stopRecording() {
    recorder.stop()
    startAudioPlayback(url: self.recordUrl)
}

@IBAction func saveToDisk(_ sender: Any) {
    if let source = self.player, let saveUrl = self.urlForDocument("pitchAudio.caf") {
        do {
            source.stop()

            let audioFile = try AKAudioFile(forWriting: saveUrl, settings: self.format.settings, commonFormat: .pcmFormatFloat64, interleaved: true)
            try AudioKit.renderToFile(audioFile, duration: source.duration, prerender: {
                source.play()
            })
            print("audio file rendered")

        } catch {
            print("error rendering", error)
        }

        // PROBLEM STARTS HERE //

        self.startAudioPlayback(url: self.recordUrl)

    }
}

public func startAudioPlayback(url:URL) {
    print("loading playback audio", url)
    self.stopEngine()

    do {
        try AKSettings.setSession(category: .playback)
        player = AKPlayer.init()
        try player.load(url: url)
    }
    catch {
        print("error setting up audio playback", error)
        return
    }

    player.prepare()
    player.isLooping = true
    self.setPitch(pitch: self.getPitch(), saveValue: false)
    AudioKit.output = player

    startEngine()
    startPlayer()
}


public func startPlayer() {
    if AudioKit.engine.isRunning { self.player.play() }
    else { print("audio engine not running, can't play") }
}

public func startEngine() {
    if !AudioKit.engine.isRunning {
        print("starting engine")
        do { try AudioKit.start() }
        catch {
            print("error starting audio", error)
        }
    }
}

public func stopEngine(){

    if AudioKit.engine.isRunning {
        print("stopping engine")
        do {
            try AudioKit.stop()
        }
        catch {
            print("error stopping audio", error)
        }
    }

    //playback doesn't work without this?
    mic = nil
}

@IBAction func changePitch(_ sender: UISlider) {
    self.setPitch(pitch:Double(sender.value))
}

public func getPitch() -> Double {
    return UserDefaults.standard.double(forKey: "pitchFactor")
}

public func setPitch(pitch:Double, saveValue:Bool = true) {
    player.pitch = pitch * 1000.0
    if saveValue {
        UserDefaults.standard.set(pitch, forKey: "pitchFactor")
        UserDefaults.standard.synchronize()
    }
}

func urlForDocument(_ named:String) -> URL? {
    let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
    let url = NSURL(fileURLWithPath: path)
    if let pathCompOnent= url.appendingPathComponent(named) {
        return pathComponent
    }
    return nil
}

}

调用的顺序是switchToMicrophone,startRecording,stopRecording,startAudioPlayback,saveToDisk,并再次,startAudioPlayback

请参阅github repo以获取ViewController.swift中的完整代码

在该renderToFile功能之后,当为播放器重新启动AudioKit时,会发生以下错误:


[mcmx] 338:输入总线0采样率为0

[avae] AVAEInternal.h:103:_AVAE_CheckNoErr:[AVAudioEngineGraph.mm:1265:Initialize :(错误= AUGraphParser :: InitializeActiveNodesInOutputChain(ThisGraph,kOutputChainOptimizedTraversal,*GetOutputNode(),isOutputChainActive)):错误-10875

[avae] AVAudioEngine.mm:149:- [AVAudioEngine准备]:引擎@ 0x1c4008ae0:无法初始化,错误= -10875

[mcmx] 338:输入总线0采样率为0

[avae] AVAEInternal.h:103:_AVAE_CheckNoErr:[AVAudioEngineGraph.mm:1265:Initialize :(错误= AUGraphParser :: InitializeActiveNodesInOutputChain(ThisGraph,kOutputChainOptimizedTraversal,*GetOutputNode(),isOutputChainActive)):错误-10875

错误启动音频错误Domain = com.apple.coreaudio.avfaudio Code = -10875"(null)"UserInfo = {failed call = err = AUGraphParser :: InitializeActiveNodesInOutputChain(ThisGraph,kOutputChainOptimizedTraversal,*GetOutputNode(),isOutputChainActive)}***

如果我将录音片段或离线渲染出来,但这两者都不包括在内,这一切都完美无缺.


推荐阅读
author-avatar
Fater-_635
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有