title: AudioKit: sync recorder, players and metronome
body: <p>I'm working on a proof of concept for <code>AudioKit</code> to evaluate if it fits our needs. </p>
  
  <p>We are currently using <code>AVAudioRecorder</code>, <code>AVPlayer</code> and <code>AVMutableComposition</code> for a multi-track recorder and it works great, but I want to try to do the same with <code>AudioKit</code> or <code>AVAudioEngine</code>.</p>
  
  <p>I'm new with <code>AudioKit</code> so I need some guidance:</p>
  
  <ol>
  <li><p>I'm using <code>AKClipRecorder</code> as the recorder and calling <code>start(at:)</code> to sync with the players, but I think something is not set properly, because there is always a delay in the recording. Why could this be happening? For the players, I'm using an array of <code>AKPlayers</code> and calling <code>play(at:)</code> to sync them, and from my tests, the players seem to sync ok.</p></li>
  <li><p>I'm having a hard time to find how to sync <code>AKMetronome</code> with the recorder and players, there is no <code>start(at:)</code> API. How can I achieve this? And is it possible to start the recorder and players in a certain beat?</p></li>
  <li><p>Lastly, is there a way to set the file format of the <code>AKClipRecorder</code>?</p></li>
  </ol>
  
  <p>I add my code below.</p>
  
  <pre><code>import Foundation
  import AudioKit
  
  class MultiTrackRecorder {
  
      // MARK: - Constants &amp; 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() -&gt; URL {
          let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
          let documentsDirectory = paths[0]
          return documentsDirectory
      }
  
      private func getDocsPathWithRandomFileName() -&gt; 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")
          }
      }
  }
  </code></pre>