AudioKit:同步录音机,播放器和节拍器

时间:2018-05-06 00:04:49

标签: audiokit audio-player metronome

我正致力于AudioKit的概念验证,以评估它是否符合我们的需求。

我们目前正在使用AVAudioRecorderAVPlayerAVMutableComposition来制作多轨录音机,效果很好,但我想尝试对AudioKit做同样的事情或AVAudioEngine

我是AudioKit的新人,所以我需要一些指导:

  1. 我使用AKClipRecorder作为录音机并呼叫start(at:)与玩家同步,但我认为某些内容设置不正确,因为总是有延迟记录。为什么会发生这种情况?对于玩家,我使用AKPlayers数组并调用play(at:)来同步它们,而在我的测试中,玩家似乎同步正常。

  2. 我很难找到如何与记录器和播放器同步AKMetronome,但没有start(at:) API。我怎样才能做到这一点?是否有可能以某种节拍启动录音机和播放器?

  3. 最后,有没有办法设置AKClipRecorder的文件格式?

  4. 我在下面添加了我的代码。

    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")
            }
        }
    }
    

1 个答案:

答案 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,其中回送音频在昨天的回购中进行了比较。