From our sponsor: Ready to show your plugin skills? Enter the Penpot Plugins Contest (Nov 15-Dec 15) to win cash prizes!
Today we’ll explore how to build a basic, line-style music visualization in the browser. We’ll be using p5.js for our drawings and its p5.sound library for analyzing sounds.
The demo is kindly sponsored by monday.com: the visual & intuitive project management and software development tool. If you would like to sponsor one of our demos, find out more here.
Analyzing Sound
When you want to make a drawing respond to an audio signal, the most basic thing you could do is to make it respond to the overall signal’s volume, its amplitude. This will give you the ability to animate your drawing, but only based on a single input. What if you would want to create different animations for the bass frequencies and for the high ones, or use a custom range of frequencies to animate different parts of your drawing? Here is where a Fast Fourier Transform can broaden your options.
At its heart FFT is an algorithm, that analyses a waveform and provides data about its different frequencies. So after you run an FFT analysis on an audio track, you can get a detailed report of its complete frequency spectrum and the amplitude of each frequency range. Then, using these different ranges, you can make your drawing respond differently for the bass, mid, or high frequencies of the signal.
The p5.sound library has a built-in FFT object, which comes in handy with a lot of useful methods depending on what you need to do. For our demos, we mostly use getEnergy()
which returns a value from 0 to 255, representing the volume of that frequency.
Running this analysis while the music plays, you can make your visuals respond to different frequencies!
// Initiate the FFT object
var fft = new p5.FFT();
// Run the analysis, while the audio is playing
fft.analyze();
// Get different values for different frequency ranges
// -----------------------------------------------------
// p5.sound comes with predefined keywords,
// but giving getEnergy() 2 numbers instead of a keyword
// you could use your custom range if needed
var bass = fft.getEnergy( "bass" );
var treble = fft.getEnergy( "treble" );
var mid = fft.getEnergy( "mid" );
var custom = fft.getEnergy( 100, 200 );
Drawing in the canvas
The main concept of all demos can be summed up in 4 parts:
- Create an initial drawing
- Analyze the audio signal
- Animate the drawing based on the different frequency ranges
- Add some visual interactions when the mouse is moved
In order to create our base drawing, we divide the circle in even pieces and draw some basic shapes around it. In the following image you can see the different options you get if you divide the circle in 4 pieces, 8 pieces, and so on (the black lines represent the effect of also going to the opposite direction for each line).
// Define in how many pieces you want to divide the circle
var pieces = 32;
// Circle's radius
var radius = 200;
// Move the origin to the center of the canvas
translate( width/2, height/2 );
// The centered circle
stroke( 0, 0, 255 );
ellipse( 0, 0, radius );
// For each piece draw a line
for( i = 0; i < pieces; i++ ) {
// Rotate the point of origin
rotate( TWO_PI / pieces );
// Draw the red lines
stroke( 255, 0, 0 );
line( 10, radius/2, 0, radius );
//Optionally also draw to the opposite direction
stroke( 0 );
line( -10, radius/2, 0, radius );
}
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
The fun part begins if you switch these static variables with a dynamic number, that constantly changes over time, like the volume of a specific frequency, the bass, the mid frequency, etc. Then you can map these values with your own custom range that fits your animation and gain complete control over the motion of your shapes.
// Run the FFT analysis
fft.analyze();
// Get the volumes of different frequency ranges
var bass = fft.getEnergy("bass");
var mid = fft.getEnergy("mid");
var treble = fft.getEnergy("treble");
// Map the range of each volume with your desired numbers
var mapBass = map( bass, 0, 255, -100, 100 );
var mapMid = map( mid, 0, 255, -150, 150 );
var mapTreble = map( treble, 0, 255, -200, 200 );
for( i = 0; i < pieces; i++ ) {
rotate( TWO_PI / pieces );
// Draw the bass lines
line( mapBass, radius/2, 0, radius );
// Draw the mid lines
line( mapMid, radius/2, 0, radius );
// Draw the treble lines
line( mapTreble, radius/2, 0, radius );
}
And that’s about it! You can play around with different shapes or different mappings and create some unique shapes that respond to your favorite music.
Keep in mind that these demos need to run on a server environment.
So awesome! This is exactly the kind of thing I have been looking for. I was not aware of the p5.sound library, which looks to be very versatile. Thank you Yannis for this inspiring post!
Is there a way to do this with realtime microphone audio?
For sure you can! Just use the p5.AudioIn and connect that to the FFT object instead. Check out this link for more info https://p5js.org/reference/#/p5.AudioIn
Cool, I might give it a try! I was thinking about using it at a party to visualize the music playing from my mixer!
Hi brother, I am trying to get this file played on my system but the screen keeps loading?
Cool, I might give it a try! I was thinking about using it at a party to visualize the music playing from my mixer!
The demo 5 was a hit for … used it as intro on my little website … respect and love for your awesome work !
I Love it!
You are not a human being
I cant believe what am seeing but thks nice work
This is such an awesome library and very good post. Can’t wait to implement this!
what is the exact genre of minimal electronic music in demo 3 and demo 5?