使用FFT执行音频分析 [英] Perform Audio Analysis with FFT

查看:692
本文介绍了使用FFT执行音频分析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在这个问题上停留了好几天了,并且已经浏览了几乎所有相关的StackOverflow页面.通过这一点,我现在对FFT是什么以及它如何工作有了更深入的了解.尽管如此,将其实现到我的应用程序中还是非常困难.

I've been stuck on this problem for days now and have looked through nearly every related StackOverflow page. Through this, I now have a much greater understanding of what FFT is and how it works. Despite this, I'm having extreme difficulties implementing it into my application.

简而言之,我要做的是为我的应用程序制作一个频谱可视化器(类似于

In short, what I am trying to do is make a spectrum visualizer for my application (Similar to this). From what I've gathered, I'm pretty sure I need to use the magnitudes of the sound as the heights of my bars. So with all this in mind, currently I am able to analyze an entire .caf file all at once. To do this, I am using the following code:

    let audioFile = try!  AVAudioFile(forReading: soundURL!)
    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 bufferSize = Int(1 << log2n)

    let fftSetup = vDSP_create_fftsetup(log2n, Int32(kFFTRadix2))

    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<DSPComplex>(buffer.floatChannelData.memory), 2, &output, 1, UInt(bufferSize / 2))

    vDSP_fft_zrip(fftSetup, &output, 1, log2n, Int32(FFT_FORWARD))

    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)

这可以正常工作,并输出一长串数据.但是,此代码的问题是它会立即分析整个音频文件.我需要分析的是正在播放的音频文件 ,类似于以下视频:频谱可视化工具.

This works fine and outputs a long array of data. However, the problem with this code is it analyzes the entire audio file at once. What I need is to be analyzing the audio file as it is playing, very similar to this video: Spectrum visualizer.

所以我想我的问题是:在音频播放期间 ,您如何执行FFT分析?

So I guess my question is this: How do you perform FFT analysis while the audio is playing?

此外,如何将FFT分析的输出转换为条形的实际高度?我从上面使用FFT分析代码获得的音频文件输出之一是: http://pastebin.com/RBLTuGx7 . pastebin的唯一原因是它的持续时间.我假设我将所有这些数字平均起来,然后改用这些值? (仅供参考,我通过在上面的代码中打印出'fft'变量来获得该数组)

Also, on top of this, how do I go about converting the output of an FFT analysis to actual heights for a bar? One of the outputs I received for an audio file using the FFT analysis code from above was this: http://pastebin.com/RBLTuGx7. The only reason for the pastebin is due to how long it is. I'm assuming I average all these numbers together and use those values instead? (Just for reference, I got that array by printing out the 'fft' variable in the code above)

我尝试通读EZAudio代码,但是我无法在实时音频样本中找到它们的读取方式.任何帮助,我们将不胜感激.

I've attempted reading through the EZAudio code, however I am unable to find how they are reading in samples of audio in live time. Any help is greatly appreciated.

推荐答案

以下是使用EZAudio的FFT工具在AudioKit中完成的方法:

Here's how it is done in AudioKit, using EZAudio's FFT tools:

为您的FFT创建一个将保存数据的类:

Create a class for your FFT that will hold the data:

@objc public class AKFFT: NSObject, EZAudioFFTDelegate {

    internal let bufferSize: UInt32 = 512
    internal var fft: EZAudioFFT?

    /// Array of FFT data
    public var fftData = [Double](count: 512, repeatedValue: 0.0)

...
}

初始化类并设置FFT.还将水龙头安装在适当的节点上.

Initialize the class and setup the FFT. Also install the tap on the appropriate node.

public init(_ input: AKNode) {
    super.init()
    fft = EZAudioFFT.fftWithMaximumBufferSize(vDSP_Length(bufferSize), sampleRate: 44100.0, delegate: self)
    input.avAudioNode.installTapOnBus(0, bufferSize: bufferSize, format: AKManager.format) { [weak self] (buffer, time) -> Void in
        if let strongSelf = self {
            buffer.frameLength = strongSelf.bufferSize;
            let offset: Int = Int(buffer.frameCapacity - buffer.frameLength);
            let tail = buffer.floatChannelData[0];
            strongSelf.fft!.computeFFTWithBuffer(&tail[offset], withBufferSize: strongSelf.bufferSize)
        }
    }
}

然后实现回调以加载内部fftData数组:

Then implement the callback to load your internal fftData array:

@objc public func fft(fft: EZAudioFFT!, updatedWithFFTData fftData: UnsafeMutablePointer<Float>, bufferSize: vDSP_Length) {
    dispatch_async(dispatch_get_main_queue()) { () -> Void in
        for i in 0...511 {
            self.fftData[i] = Double(fftData[i])
        }
    }
}

AudioKit的实现可能会更改,因此您应该检查 https://github.com/audiokit/AudioKit/查看是否进行了任何改进. EZAudio位于 https://github.com/syedhali/EZAudio

AudioKit's implementation may change so you should check https://github.com/audiokit/AudioKit/ to see if any improvements were made. EZAudio is at https://github.com/syedhali/EZAudio

这篇关于使用FFT执行音频分析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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