Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FFT buffer size / scale #748

Closed
steve228uk opened this issue Feb 15, 2017 · 9 comments
Closed

FFT buffer size / scale #748

steve228uk opened this issue Feb 15, 2017 · 9 comments

Comments

@steve228uk
Copy link

Hello! Apologies if this is the incorrect place and may belong more on StackOverflow.

We're working to build a spectrum analyser and are using AKFFTTap. It's working great and we're getting the expect 512 points in the data.

This is my first time working with audio and I have a few questions:

  1. How do I calculate the max point on the Y axis?
  2. Is it possible to reduce the number of nodes returned? i.e. 8 bars instead of 512
  3. What is the scale on the X axis? i.e. How can the frequency labels be calculated?
  4. When using the AKNodeFFTPlot the right of the graph never seems to be used. I'm assuming this is related to the 512 points returned from AKFFTTap containing mostly zero values. If this is the case is there a way they can be ignored and the X axis size reduced?

Thanks again for an awesome framework and apologies if this is the wrong place 😄

@steve228uk
Copy link
Author

Okay it seems I've been able to reduce the number of node by manually cloning AKFFTTap and reducing the buffer size. Looking at the AKSettings there is a bufferSize option there. Should this not be used as it defaults to 1024 samples anyway

https://github.com/audiokit/AudioKit/blob/master/AudioKit/Common/Internals/AKSettings.swift#L18-L37

import Foundation
import AudioKit

class CustomTap: NSObject, EZAudioFFTDelegate {
    
    internal let bufferSize: UInt32 = 32
    internal var fft: EZAudioFFT?
    
    /// Array of FFT data
    open var fftData = [Double](zeros: 16)
    
    /// Initialze the FFT calculation on a given node
    ///
    /// - parameter input: Node on whose output the FFT will be computed
    ///
    public init(_ input: AKNode) {
        super.init()
        fft = EZAudioFFT(maximumBufferSize: vDSP_Length(bufferSize), sampleRate: Float(AKSettings.sampleRate), delegate: self)
        input.avAudioNode.installTap(onBus: 0, bufferSize: bufferSize, format: AudioKit.format) { [weak self] (buffer, time) -> Void in
            guard let strongSelf = self else { return }
            buffer.frameLength = strongSelf.bufferSize
            let offset = Int(buffer.frameCapacity - buffer.frameLength)
            let tail = buffer.floatChannelData?[0]
            strongSelf.fft!.computeFFT(withBuffer: &tail![offset],
                                       withBufferSize: strongSelf.bufferSize)
        }
    }
    
    /// Callback function for FFT computation
    @objc open func fft(_ fft: EZAudioFFT!, updatedWithFFTData fftData: UnsafeMutablePointer<Float>, bufferSize: vDSP_Length) {
        DispatchQueue.main.async { () -> Void in
            for i in 0..<16 {
                self.fftData[i] = Double(fftData[i])
            }
        }
    }
}

@steve228uk
Copy link
Author

steve228uk commented Feb 15, 2017

It also looks like AKNodeFFTPlotter also sets a buffer size of 1024 but unlike AKFFTTap does not half the number of elements to 512. Not sure if this is correct.

https://github.com/audiokit/AudioKit/blob/master/AudioKit/Common/User%20Interface/AKNodeFFTPlot.swift#L33

This line accesses self.bufferSize whereas the local bufferSize argument passed through is half of the main buffer size. This seems to be the reason as to why only half of the graph is ever populated.

@steve228uk
Copy link
Author

Reducing the buffer size in AKNodeFFTPlotter does seem to cause the delay as document in this issue though.

#658

@aure
Copy link
Member

aure commented Feb 17, 2017

Hi Steve, you're probably the person who will be delving into the internals of AudioKit the most. If you see something worth adding or fixing, please feel free. You've answered some of your own questions here so maybe you can re-ask what you most need to know. But here's a shot:

Q1. The y-axis is relative magnitudes, you should be able to iterate through them to find the max.
Q3. Not sure, I believe there are sample rate / 2 / size buckets, and then each one would be exponentially bigger than the next.
Q4. It would be a great enhancement to the plot to do these things. Could you would you? Please?

Thanks!

@steve228uk
Copy link
Author

Thanks @aure.

Q1. Awesome, that might be tricky to do each time so I'll set a sensible default.
Q3/4. It seems to be a default of 1024 buckets regardless of sample rate on a linear scale. Most spectrum analysers use a logarithmic scale which is why it seems that some of the graph is unused. I've uploaded an example of this below. As you can see the graph gets tighter toward the higher frequencies. Is such a scale possible with EZPlotter?

unnamed-1

@aure
Copy link
Member

aure commented Feb 19, 2017

I'm sure its possible, just not automatic/currently built.

@aure
Copy link
Member

aure commented Feb 26, 2017

I'm going to close this for now, but if there's an actionable issue to sort out, just post some more information and reopen this issue. thanks.

@aure aure closed this as completed Feb 26, 2017
@CodingMeSwiftly
Copy link

CodingMeSwiftly commented Apr 22, 2017

It might be worth looking into Constant Q Transform for this:
http://doc.ml.tu-berlin.de/bbci/material/publications/Bla_constQ.pdf

Basically, you see so many "peaks" on the left because FFT output is logarithmic but you plot it on a linear axis (As far as I've understood so far - I'm a DSP newbie myself :D)

What I want to build is a software version of this:
https://www.youtube.com/watch?v=Vn39txtVIHc&t=14s
(It's a long watch, but hell it's absolutely worth it!)
The genius in this video states that he used Constant Q Transform to extract Keyboard notes (C1 - C8) from the audio signal. I assume this is what you mean by Q2 [Number of bars].

I've started working on this a few days ago but tbh I'm a bit scared of the maths going on in there.
There is even a library [C++] for usage in iOS / macOS. It leverages Accelerate just like EZFFT:
https://github.com/mattrajca/CQTKit

However, as I said I've not been able to get this stuff running in a satisfying manner, yet.

@denisb411
Copy link

Greetings @ImJCabus,

I'm very interested at a Constant Q Transform algorithm implemented at swift. Do tou think there's something there or just C/C++ codes?
AKFrequencyTracker probably uses autocorrelation (as this algorithm was written by M. Puckket and it's stated at the document) and unfortunately it's not as good as Constant Q Transform at low frequencies (< 100 Hz).
So in order to perfect make a tuner for guitar/bass I need to improve the fundamental frequency tracking...

If you hear something please comment here.

Reference for this conclusion:
http://dafx10.iem.at/papers/VonDemKnesebeckZoelzer_DAFx10_P102.pdf
http://www.cs.otago.ac.nz/tartini/papers/A_Smarter_Way_to_Find_Pitch.pdf
Good lecture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants