Swift FFT - 复杂分裂问题 [英] Swift FFT - Complex split issue

查看:179
本文介绍了Swift FFT - 复杂分裂问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试在音频文件上执行 FFT ,以使用Accelerate框架查找频率。我从这个问题中修改了代码(可能是错误的):使用AVAudioPCMBuffer的频谱图加速Swift中的框架

I am trying to perform FFT on an audio file to find frequency using the Accelerate framework. I have adapted code (probably wrong) from this question: Spectrogram from AVAudioPCMBuffer using Accelerate framework in Swift

虽然频谱的幅度要么是 0 ,' inf '或' nan ',以及复合体的' real '和' imag '组件拆分打印类似的结果;表明这是导致问题的原因:' magnitude = sqrt(pow(真实,2)+ pow( imag ,2)如果我错了,请纠正我,但我认为剩下的代码还可以。

Although, the magnitudes from 'spectrum' are either '0', 'inf' or 'nan', and the 'real' and 'imag' components of the complex split print similar results; indicating that this is the cause of the problem as: 'magnitude = sqrt(pow(real,2)+pow(imag,2)'. Correct me if i'm wrong, but I think the rest of the code is ok.

为什么我会收到这些结果以及如何修复它(拆分组件应该是什么),以及我做错了什么?请记住,我是FFT和采样的新手,并且还没有弄清楚如何为音频文件设置它,所以任何帮助将不胜感激。谢谢。

Why am I receiving these results and how can I fix it (what should the split components be), and what am I doing wrong? Please keep in mind that I am very new to FFT and sampling and haven't got a clue how to set this up for an audio file, so any help would be greatly appreciated. Thanks.

这是我正在使用的代码:

Here's the code i'm using:

    // get audio file
    let fileURL:NSURL = NSBundle.mainBundle().URLForResource("foo", withExtension: "mp3")!
    let audioFile = try!  AVAudioFile(forReading: fileURL)
    let fileFormat = audioFile.processingFormat
    let frameCount = UInt32(audioFile.length)

    let buffer = AVAudioPCMBuffer(PCMFormat: fileFormat, frameCapacity: frameCount)
    let audioEngine = AVAudioEngine()
    let playerNode = AVAudioPlayerNode()
    audioMixerNode = audioEngine.mainMixerNode

    let bufferSize = Int(frameCount)
    let channels: NSArray = [Int(buffer.format.channelCount)]
    let channelCount = channels.count
    let floats1 = [Int(buffer.frameLength)]
    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]))
        }
    }

    // connect node
    audioEngine.attachNode(playerNode)
    audioEngine.connect(playerNode, to: audioMixerNode, format: playerNode.outputFormatForBus(0))

    // 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
    // why doesn't this work?
    var realp = [Float](count: bufferSize/2, repeatedValue: 0)
    var imagp = [Float](count: bufferSize/2, repeatedValue: 0)
    var output = DSPSplitComplex(realp: &realp, imagp: &imagp)

    vDSP_ctoz(UnsafePointer(channelSamples), 2, &output, 1, UInt(bufferSize / 2))

    // Do the fast Fourier 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)
    let bufferOver2: vDSP_Length = vDSP_Length(bufferSize / 2)
    vDSP_zvmags(&output, 1, &fft, 1, bufferOver2)

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

    // Release the setup
    vDSP_destroy_fftsetup(fftSetup)


推荐答案

您的代码存在以下几个问题:

There were a couple of problems with your code:


  1. 您没有阅读音频文件样本

  2. channelSamples包装不正确

  3. vDSP_fft_zrip 正在超出数组末尾读取。它预计2 ^ log2n样本

  4. vDSP_fft_zrip 的输出是已打包并且您的计算结果是unpacked

  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

let fileURL:NSURL = NSBundle.mainBundle().URLForResource("foo", withExtension: "mp3")!
let audioFile = try!  AVAudioFile(forReading: fileURL)
let frameCount = UInt32(audioFile.length)

let buffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: frameCount)
do {
    try audioFile.readIntoBuffer(buffer, frameCount:frameCount)
} catch {

}
let log2n = UInt(round(log2(Double(frameCount))))

let bufferSizePOT = Int(1 << log2n)

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

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

vDSP_ctoz(UnsafePointer<DSPComplex>(buffer.floatChannelData.memory), 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](count:Int(bufferSizePOT / 2), repeatedValue:0.0)
let bufferOver2: vDSP_Length = vDSP_Length(bufferSizePOT / 2)
vDSP_zvmags(&output, 1, &fft, 1, bufferOver2)


// Release the setup
vDSP_destroy_fftsetup(fftSetup)


这篇关于Swift FFT - 复杂分裂问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆