AudioKit - как получить данные floatChannelData в реальном времени с микрофона?

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

Я знаю, что данные, которые мне нужны, находятся в AKAudioFile FloatChannelData, но что, если я хочу получить их в режиме реального времени? В настоящее время я использую 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) и вы хотите вывести эти значения на метку?


person Ranknoodle    schedule 11.06.2018    source источник


Ответы (2)


Используйте касание к любому узлу, из которого вы хотите получить данные. Я использовал 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», где он строится, но вместо этого вы делаете что-то еще.

person Aurelius Prochazka    schedule 12.06.2018
comment
Спасибо за ответ! Я тоже видел эту часть вашего кода, и это тоже помогло. github.com/AudioKit/AudioKit/tree/master/AudioKit/Common/ Касания - person Ranknoodle; 13.06.2018
comment
что нам говорит это смещение? зачем нам это использовать? - person Martin Mlostek; 12.07.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 tap 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)
}

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

person Jeremy Cochoy    schedule 07.05.2019