Спектрограмма из AVAudioPCMBuffer с использованием Accelerate Framework в Swift

Я пытаюсь сгенерировать спектрограмму изAVAudioPCMBuffer в Свифте. Я устанавливаю кран наAVAudioMixerNode и получить обратный вызов с аудио буфером. Я хотел бы преобразовать сигнал в буфере в[Float:Float] словарь, где ключ представляет частоту, а значение представляет величину звука на соответствующей частоте.

Я пытался использовать Apple Accelerate Framework, но результаты, которые я получаю, кажутся сомнительными. Я уверен, что именно так я преобразовываю сигнал.

я смотрел наэтот блог среди прочего для справки.

Вот что у меня есть:

self.audioEngine.mainMixerNode.installTapOnBus(0, bufferSize: 1024, format: nil, block: { buffer, when in
    let bufferSize: Int = Int(buffer.frameLength)

    // Set up the transform
    let log2n = UInt(round(log2(Double(bufferSize))))
    let fftSetup = vDSP_create_fftsetup(log2n, Int32(kFFTRadix2))

    // Create the complex split value to hold the output of the transform
    var realp = [Float](count: bufferSize/2, repeatedValue: 0)
    var imagp = [Float](count: bufferSize/2, repeatedValue: 0)
    var output = DSPSplitComplex(realp: &realp, imagp: &imagp)

    // Now I need to convert the signal from the buffer to complex value, this is what I'm struggling to grasp.
    // The complexValue should be UnsafePointer<DSPComplex>. How do I generate it from the buffer's floatChannelData?
    vDSP_ctoz(complexValue, 2, &output, 1, UInt(bufferSize / 2))

    // Do the fast Fournier forward transform
    vDSP_fft_zrip(fftSetup, &output, 1, log2n, Int32(FFT_FORWARD))

    // Convert the complex output to magnitude
    var fft = [Float](count:Int(bufferSize / 2), repeatedValue:0.0)
    vDSP_zvmags(&output, 1, &fft, 1, vDSP_length(bufferSize / 2))

    // Release the setup
    vDSP_destroy_fftsetup(fftsetup)

    // TODO: Convert fft to [Float:Float] dictionary of frequency vs magnitude. How?
})
Мои вопросыКак мне конвертироватьbuffer.floatChannelData&nbsp;вUnsafePointer<DSPComplex>&nbsp;перейти кvDSP_ctoz&nbsp;функционировать? Есть ли другой / лучший способ сделать это, возможно, даже в обходvDSP_ctoz?Отличается ли это, если буфер содержит аудио из нескольких каналов? Чем он отличается, когда данные буферного аудиоканала чередуются или не чередуются?Как мне конвертировать индексы вfft&nbsp;массив частот в Гц?Что-то еще я могу делать не так?Обновить

Спасибо всем за предложения. В итоге я заполнил сложный массив, как предложено в принятом ответе. Когда я строю значения и играю тон 440 Гц на камертоне, он регистрируется именно там, где и должен.

Вот код для заполнения массива:

var channelSamples: [[DSPComplex]] = []
for var i=0; i<channelCount; ++i {
    channelSamples.append([])
    let firstSample = buffer.format.interleaved ? i : i*bufferSize
    for var j=firstSample; j<bufferSize; j+=buffer.stride*2 {
        channelSamples[i].append(DSPComplex(real: buffer.floatChannelData.memory[j], imag: buffer.floatChannelData.memory[j+buffer.stride]))
    }
}

channelSamples&nbsp;Затем массив содержит отдельный массив выборок для каждого канала.

Для расчета величины я использовал это:

var spectrum = [Float]()
for var i=0; i<bufferSize/2; ++i {
    let imag = out.imagp[i]
    let real = out.realp[i]
    let magnitude = sqrt(pow(real,2)+pow(imag,2))
    spectrum.append(magnitude)
}