Espectrograma do AVAudioPCMBuffer usando o framework Accelerate no Swift

Estou tentando gerar um espectrograma de umAVAudioPCMBuffer em Swift. Eu instalo uma torneira em umAVAudioMixerNode e receba um retorno de chamada com o buffer de áudio. Eu gostaria de converter o sinal no buffer em um[Float:Float] dicionário em que a tecla representa a frequência e o valor representa a magnitude do áudio na frequência correspondente.

Tentei usar o framework Accelerate da Apple, mas os resultados parecem duvidosos. Tenho certeza de que está apenas no caminho em que estou convertendo o sinal.

Eu olheiesta postagem no blog entre outras coisas para uma referência.

Aqui está o que eu tenho:

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?
})
Minhas perguntas sãoComo faço para converter obuffer.floatChannelData paraUnsafePointer<DSPComplex> passar para ovDSP_ctoz função? Existe uma maneira diferente / melhor de fazê-lo, talvez até ignorandovDSP_ctoz?Isso é diferente se o buffer contiver áudio de vários canais? Qual é a diferença quando os dados do canal de áudio do buffer são ou não são intercalados?Como faço para converter os índices nofft matriz para frequências em Hz?Mais alguma coisa que eu possa estar fazendo de errado?Atualizar

Obrigado a todos por sugestões. Acabei preenchendo a matriz complexa, conforme sugerido na resposta aceita. Quando plogo os valores e reproduzo um tom de 440 Hz em um diapasão, ele registra exatamente onde deveria.

Aqui está o código para preencher a matriz:

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

ochannelSamples A matriz mantém uma matriz separada de amostras para cada canal.

Para calcular a magnitude, usei isso:

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

questionAnswers(2)

yourAnswerToTheQuestion