使用FFT执行音频分析
几天以来我一直坚持这个问题,并查看了几乎所有相关的StackOverflow页面。 通过这一点,我现在对FFT是什么以及它是如何工作有了更多的了解。 尽管如此,我在将其应用到我的应用程序中时遇到了极大的困难。
简而言之,我要做的是为我的应用程序制作一个频谱可视化器(与此类似)。 从我收集到的,我很确定我需要使用声音的大小作为我的酒吧的高度。 所以考虑到所有这些,目前我能够一次性分析整个.caf文件。 为此,我使用以下代码:
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(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)
这很好,并输出一长串数据。 但是,此代码的问题是它会立即分析整个音频文件。 我需要的是在播放时分析音频文件,与此video非常相似: Spectrum visualizer 。
所以我想我的问题是:在音频播放时如何进行FFT分析?
此外,除此之外,我如何将FFT分析的输出转换为条形码的实际高度? 我使用上面的FFT分析代码收到的音频文件的输出之一是: http : //pastebin.com/RBLTuGx7 。 pastebin的唯一原因是由于它有多长。 我假设我将所有这些数字平均并使用这些值而不是? (仅供参考,我通过在上面的代码中打印出’fft’变量来获得该数组)
我试图通过EZAudio代码阅读,但我无法找到他们如何在实时时间读取音频样本。 任何帮助是极大的赞赏。
以下是使用EZAudio的FFT工具在AudioKit中完成的工作:
为您的FFT创建一个用于保存数据的类:
@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。 同时在适当的节点上安装水龙头。
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数组:
@objc public func fft(fft: EZAudioFFT!, updatedWithFFTData fftData: UnsafeMutablePointer, 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