Learn how to display incoming audio data as a spectrogram by using the FFT class of the DSP module. Understand the benefits of using a Fast Fourier Transform.
Level: Intermediate
Platforms: Windows, macOS, Linux
Classes: dsp::FFT, Image, Colour, FloatVectorOperations
Download the demo project for this tutorial here: PIP | ZIP. Unzip the project and open the first header file in the Projucer.
If you need help with this step, see Tutorial: Projucer Part 1: Getting started with the Projucer.
When completed, the demo project will display the incoming audio data as a three-dimensional spectrogram in the time (x-axis), frequency (y-axis) and amplitude (colour) domains. The values displayed on the screen will be updated 60 times a second and the window at any time frame may look something like this:
A time or space domain signal can be converted to the frequency domain by using a transformation formula called the Fourier transform. A common efficient implementation of this transformation function is the Fast Fourier Transform or FFT, which is included in the JUCE DSP module and which we will use in this tutorial.
The FFT allows us to decompose an audio signal into its frequencies and represent the magnitude and phase information for each of these frequencies. Using its inverse function, we can revert the signal into its original domain thus making it really useful to process individual frequency components such as for filtering.
Since this tutorial only deals with displaying the audio data without actual processing for output, we focus on the forward FFT rather than the inverse FFT.
Currently our application does not display nor process any incoming audio signals so let's start by implementing the FFT.
In the SpectrogramComponent
class, start by defining some useful constants for the FFT implementation:
Next, declare private member variables required for the FFT implementation as shown below:
Now let's initialise these variables in the member initialisation list of our constructor like so:
The FFT object has to be explicitly initialised with the correct order at this point.
In the overriden getNextAudioBlock()
function, we simply push all the samples contained in our current audio buffer block to the fifo to be processed at a later time:
To push the sample into the fifo, implement the pushNextSampleIntoFifo()
function as described below:
The fifo data now occupies the first half of the FFT input array and is ready to be processed and displayed.
In the drawNextLineOfSpectrogram()
function, insert the pixel drawing implementation as explained below:
moveImageSection()
function on the Image object. Specify the image section as the whole width minus one pixel and the whole height.performFrequencyOnlyForwardTransform()
function on the FFT object with the fftData array as an argument.As a final step, update the spectrogram using the timer callback function by calling the drawNextLineOfSpectrogram()
only when the next FFT block is ready, reset the flag and update the GUI using the repaint()
function:
SimpleFFTTutorial_02.h
file of the demo project.In this tutorial, we have learnt how to use an FFT function to display audio data in a spectrogram. In particular, we have: