Swift FFT - Complex split issue

心不动则不痛 提交于 2019-12-03 00:53:13

There were a couple of problems with your code:

  1. you weren't reading in the audio file samples
  2. channelSamples was packed incorrectly
  3. vDSP_fft_zrip was reading beyond the end of the array. it expects 2^log2n samples
  4. vDSP_fft_zrip's output is packed and your calculations expect unpacked

Swift 4 version now with actual fix for point 3

let fileURL = Bundle.main.url(forResource: "foo", withExtension: "mp3")!
let audioFile = try!  AVAudioFile(forReading: fileURL as URL)
let frameCount = UInt32(audioFile.length)

let log2n = UInt(round(log2(Double(frameCount))))
let bufferSizePOT = Int(1 << log2n)

let buffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: AVAudioFrameCount(bufferSizePOT))!
try! audioFile.read(into: buffer, frameCount:frameCount)

// Not sure if AVAudioPCMBuffer zero initialises extra frames, so when in doubt...
let leftFrames = buffer.floatChannelData![0]
for i in Int(frameCount)..<Int(bufferSizePOT) {
    leftFrames[i] = 0
}

// Set up the transform
let fftSetup = vDSP_create_fftsetup(log2n, Int32(kFFTRadix2))!

// create packed real input
var realp = [Float](repeating: 0, count: bufferSizePOT/2)
var imagp = [Float](repeating: 0, count: bufferSizePOT/2)
var output = DSPSplitComplex(realp: &realp, imagp: &imagp)

leftFrames.withMemoryRebound(to: DSPComplex.self, capacity: bufferSizePOT / 2) {
    vDSP_ctoz($0, 2, &output, 1, UInt(bufferSizePOT / 2))
}

// Do the fast Fourier forward transform, packed input to packed output
vDSP_fft_zrip(fftSetup, &output, 1, log2n, Int32(FFT_FORWARD))

// you can calculate magnitude squared here, with care
// as the first result is wrong! read up on packed formats
var fft = [Float](repeating:0.0, count:Int(bufferSizePOT / 2))
vDSP_zvmags(&output, 1, &fft, 1, vDSP_Length(bufferSizePOT / 2))

// Release the setup
vDSP_destroy_fftsetup(fftSetup)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!