AudioKit - Как получить в реальном времени floatChannelData от микрофона? - PullRequest
0 голосов
/ 11 июня 2018

Я новичок в Audiokit и пытаюсь выполнить некоторую цифровую обработку сигналов в реальном времени при вводе звука с микрофона.

Я знаю, что данные, которые мне нужны, находятся в FloatChannelData AKAudioFile, но что еслиЯ хочу получить это в режиме реального времени?В настоящее время я использую AKMicrophone, AKFrequencyTracker, AKNodeOutputPlot, AKBooster и строю графики данных амплитуды трекера.Однако эти данные не совпадают с аудиосигналом (как вы знаете, это RMS).Можно ли как-нибудь получить данные с плавающего сигнала с микрофона?Или даже из AKNodeOutputPlot?Мне просто нужен доступ для чтения.

AKSettings.audioInputEnabled = true
mic = AKMicrophone()
plot = AKNodeOutputPlot(mic, frame: audioInputPlot.bounds)
tracker = AKFrequencyTracker.init(mic)
silence = AKBooster(tracker,gain:0)
AudioKit.output = silence
AudioKit.start()

Создатель рекомендует здесь :

AKNodeOutputPlot работает, его один короткий файл.Вы просто нажимаете на узел и захватываете данные.

Как это будет работать в моем viewController, если у вас есть экземпляр plot (AKNodeOutputPlot), mic (AKMicrophone) и вы хотите вывести эти значенияна этикетку?

Ответы [ 2 ]

0 голосов
/ 08 мая 2019

Чтобы завершить ответ Аврелия Прохазки:

Чтобы записать звук, проходящий через узел, вам необходимо прикрепить к нему ленту.Лента - это просто замыкание, которое вызывается каждый раз, когда доступен буфер.

Вот пример кода, который вы можете повторно использовать в своем собственном классе:

var mic = AKMicrophone()

func initMicrophone() {

  // Facultative, allow to set the sampling rate of the microphone
  AKSettings.sampleRate = 44100

  // Link the microphone note to the output of AudioKit with a volume of 0.
  AudioKit.output = AKBooster(mic, gain:0)

  // Start AudioKit engine
  try! AudioKit.start()

  // Add a tape to the microphone
  mic?.avAudioNode.installTap(
      onBus: audioBus, bufferSize: 4096, format: nil // I choose a buffer size of 4096
  ) { [weak self] (buffer, _) in //self is now a weak reference, to prevent retain cycles

      // We try to create a strong reference to self, and name it strongSelf
      guard let strongSelf = self else {
        print("Recorder: Unable to create strong reference to self #1")
        return
      }

      // We look at the buffer if it contains data
      buffer.frameLength = strongSelf.bufferSize
      let offset = Int(buffer.frameCapacity - buffer.frameLength)
      if let tail = buffer.floatChannelData?[0] {
        // We convert the content of the buffer to a swift array
        let samples = Array(UnsafeBufferPointer(start: &tail[offset], count: 4096))
        strongSelf.myFunctionHandlingData(samples)
      }
  }

  func myFunctionhandlingData(data: [Float]) {
    // ...
  }

Будьте осторожны при использовании DispatchQueue или другой механизм синхронизации, если вам нужно взаимодействовать с этими данными между различными потоками.В моем случае я использую:

DispatchQueue.main.async { [weak self]  in
  guard let strongSelf = self else {
    print("Recorder: Unable to create strong reference to self #2")
    return
  }
  strongSelf.myFunctionHandlingData(samples)
}

, чтобы моя функция выполнялась в главном потоке.

0 голосов
/ 12 июня 2018

Используйте касание, на каком узле вы хотите получить данные.Я использовал AKNodeOutputPlot в приведенной выше цитате, потому что это довольно просто, просто используя эти данные в качестве входных данных для графика, но вы можете взять данные и делать с ними что угодно.В этом коде (из AKNodeOutputPlot ):

internal func setupNode(_ input: AKNode?) {
    if !isConnected {
        input?.avAudioNode.installTap(
            onBus: 0,
            bufferSize: bufferSize,
            format: nil) { [weak self] (buffer, _) in

                guard let strongSelf = self else {
                    AKLog("Unable to create strong reference to self")
                    return
                }
                buffer.frameLength = strongSelf.bufferSize
                let offset = Int(buffer.frameCapacity - buffer.frameLength)
                if let tail = buffer.floatChannelData?[0] {
                    strongSelf.updateBuffer(&tail[offset], withBufferSize: strongSelf.bufferSize)
                }
        }
    }
    isConnected = true
}

Вы получаете данные буфера в режиме реального времени.Здесь мы просто отправляем его в «updateBuffer», где он отображается, но вместо того, чтобы создавать, вы должны сделать что-то еще.

...