Swift FFT - 复杂分裂问题 [英] Swift FFT - Complex split issue
问题描述
我正尝试在音频文件上执行 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:
- 您没有阅读音频文件样本
- channelSamples包装不正确
-
vDSP_fft_zrip
正在超出数组末尾读取。它预计2 ^ log2n样本 -
vDSP_fft_zrip
的输出是已打包并且您的计算结果是unpacked
- you weren't reading in the audio file samples
- channelSamples was packed incorrectly
vDSP_fft_zrip
was reading beyond the end of the array. it expects 2^log2n samplesvDSP_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屋!