[英]AudioKit 4.3: record audio, render it offline, then play it
我想錄制音頻,然后使用離線保存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)} ***
如果我將錄音片段或離線渲染出來,但這兩者都不包括在內,這一切都完美無缺。
可能是你的執行順序問題是嘗試交換startAudioPlayback,saveToDisk,以便它首先執行saveToDisk,然后讀取文件並播放它,startAudioPlayback。
編輯:到目前為止,通過玩它我相信我已經確定了這個問題。 保存文件后,由於某種原因,錄制的其他臨時文件正在消失。 我認為需要縮小其原因。
或者也許是播放並將整個saveToDisk方法發送到后台線程而不會中斷當前播放的文件。
在業余時間,我會嘗試稍微調整一下,讓你知道。
編輯2:檢查此https://stackoverflow.com/a/48133092/9497657,如果你無處可試在這里發布你的問題: https : //github.com/audiokit/AudioKit/issues/
也請查看本教程: https : //www.raywenderlich.com/145770/audiokit-tutorial-getting-started
也可能有用的消息Aurelius Prochazka,因為他是AudioKit的開發者,可以提供幫助。
通過將錄制和回放組合到一個管道中,我能夠將其工作:
mixer = AKMixer(mic)
boostedMic = AKBooster(mixer, gain: 5)
amplitudeTracker = AKAmplitudeTracker(boostedMic)
micBooster = AKBooster(amplitudeTracker, gain: 0)
player = AKPlayer()
try? player.load(url: self.recordUrl)
player.prepare()
player.gain = 2.0
outputMixer = AKMixer(micBooster, player)
AudioKit.output = outputMixer
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.