我正致力于AudioKit
的概念验证,以评估它是否符合我们的需求。
我们目前正在使用AVAudioRecorder
,AVPlayer
和AVMutableComposition
来制作多轨录音机,效果很好,但我想尝试对AudioKit
做同样的事情或AVAudioEngine
。
我是AudioKit
的新人,所以我需要一些指导:
我使用AKClipRecorder
作为录音机并呼叫start(at:)
与玩家同步,但我认为某些内容设置不正确,因为总是有延迟记录。为什么会发生这种情况?对于玩家,我使用AKPlayers
数组并调用play(at:)
来同步它们,而在我的测试中,玩家似乎同步正常。
我很难找到如何与记录器和播放器同步AKMetronome
,但没有start(at:)
API。我怎样才能做到这一点?是否有可能以某种节拍启动录音机和播放器?
最后,有没有办法设置AKClipRecorder
的文件格式?
我在下面添加了我的代码。
import Foundation
import AudioKit
class MultiTrackRecorder {
// MARK: - Constants & Vars
private var mic: AKMicrophone!
private var micBooster: AKBooster!
private var mainMixer: AKMixer!
private var recorder: AKClipRecorder!
private var players: [AKPlayer] = []
private var metronome: AKMetronome!
// MARK: - Public Methods
func startEngine() throws {
AKSettings.bufferLength = .medium
AKSettings.defaultToSpeaker = true
try AKSettings.setSession(category: .playAndRecord)
mic = AKMicrophone()
recorder = AKClipRecorder(node: mic)
micBooster = AKBooster(mic)
micBooster.gain = 0
metronome = AKMetronome()
metronome.tempo = 120
mainMixer = AKMixer()
mainMixer.connect(input: micBooster)
mainMixer.connect(input: metronome)
AudioKit.output = mainMixer
try AudioKit.start()
}
func startRecording() throws {
try recorder.recordClip(completion: recordingEnded)
let startTime = AVAudioTime.now() + 0.25
recorder.start(at: startTime)
players.forEach { $0.play(at: startTime) }
//metronome.start()
}
func stopRecording() {
recorder.stopRecording()
recorder.stop()
players.forEach { $0.stop() }
metronome.stop()
}
func play() {
let startTime = AVAudioTime.now() + 0.25
players.forEach { $0.play(at: startTime) }
}
func stop() {
players.forEach { $0.stop() }
}
// MARK: - Private Methods
private func addPlayer(withFileURL url: URL) {
guard let player = AKPlayer(url: url) else { return }
players.append(player)
mainMixer.connect(input: player)
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
private func getDocsPathWithRandomFileName() -> URL {
let docsDirectory = getDocumentsDirectory()
let fileName = "\(UUID().uuidString).caf"
return docsDirectory.appendingPathComponent(fileName, isDirectory: false)
}
private func recordingEnded(url: URL?, somethimg: Double, error: Error?) {
guard let savedFile = url else {
print("TODO: Handle this error")
return
}
do {
let moveToDirectory = getDocsPathWithRandomFileName()
try FileManager.default.moveItem(at: savedFile, to: moveToDirectory)
addPlayer(withFileURL: moveToDirectory)
print("New track has been saved in: \(moveToDirectory.absoluteString)")
} catch {
print("TODO: Handle this error")
}
}
}
答案 0 :(得分:3)
尝试AKSamplerMetronome而不是AKMetronome,它有一个play(at :)功能。
至于正确的时机,有一些事情在起作用。 AKMicrophone不会提供正确的时间戳,请改用AudioKit.engine.inputNode。如果你真的希望它准确,你将需要补偿io延迟。
let startTime = AVAudioTime.now() + 0.25
let audioSession = AVAudioSession.sharedInstance()
// start players in advance to compensate for hardware output latency
let playbackStart = startTime - audioSession.outputLatency
//start recorders late to compensate for hardware input latency.
let recordingStart = startTime + audioSession.inputLatency
我刚刚发布了一个example,其中回送音频在昨天的回购中进行了比较。