Making a Music Visualization with P5JS

Written by nadya-primak | Published 2020/04/17
Tech Story Tags: creativity | data-visualization | creating-visualizations | generative-art | digital-art | image-processing | creative-technologists | hackernoon-top-story | web-monetization

TLDR P5JS is a version of Processing that is ported to Javascript. It is built on top of Python and is used to create generative art, visualizations, and immersive installations. The first session was a tutorial on how to use the language. I hope to translate the tutorial into a written format, for posterity and to share what I learned. I had the immense pleasure of attending several creative coding workshops on April 4th. There were additional sessions involving Hydra, Raspberry Pi, Haskell, and more.via the TL;DR App

I had the immense pleasure of attending several creative coding workshops on April 4th. They were streamed live on the SpacyCloud Twitch channel. There were additional sessions involving Hydra, Raspberry Pi, Haskell, and more. However for this post I want to focus on the first session which was a P5JS tutorial. In this post I hope to translate the P5JS tutorial into a written format, for posterity and to share what I learned. I'm going to review what was taught in the live session. Hopefully SpacyCloud will have another live stream in the future so I can catch up on what I missed. Here is the landing page for the event schedule.
Although I have used Processing years ago when I was in college, I knew I was very rusty which is why I decided to tune into Leandra T's P5JS tutorial stream. Originally branded as a creative coding language for artists, Processing is mainly used to create generative art, visualizations, and immersive installations. P5JS is basically a version of Processing that is ported to Javascript. Processing was developed by MIT and is built on top of Python. Naturally people wanted to be able to show their generative art online, so it didn't take long for there to be a huge demand for Processing that worked with Javascript instead of Python. Since P5JS has taken off there is tons of code online that people are sharing, making it a lot easier to learn.
That being said, it’s still nice to have someone walk through every step with you. That is what Leandra did. After showing us an example of what we were going to make, Leandra dived right into the online P5 editor. Whats great about this editor is you can do all of your coding online and see the results of your code side by side. She went over some of the basic functions, such as setting the canvas and background, and drawing shapes.
In the above code (to be more precise, a screenshot from the aforementioned P5 editor) you can see two functions, setup and draw. The setup function is called once when the application first runs, while draw is called constantly every frame (at least 24 times per second). What that means is that while it looks like the circle is static, it’s actually being redrawn constantly. However our eye cannot perceive that so it looks as though the circle is always there.
As you might have guessed, 
createCanvas
 is only called once and the two numbers you pass are the pixel width and height of the canvas, respectively. The canvas defines the area within which you can draw. Inside the draw function, background is what defines the background color of your canvas. If you pass 1 number, you will get a shade of gray as if you passed 3 RGB (red, green, blue) values.
That means that 
background(220)
 is just shorthand for
background(220,220,220)
. Each value can be as high as 255 (white) or as low as 0 (black).
Then of course you have the ellipse. In the screenshot above there are only 3 values passed to the 
ellipse
 function: x coordinate, y coordinate, and radius. However, you can actually pass in 4 values, which is why the function is called ellipse rather than circle. Passing in 4 values means you can stretch or squish the shape because you are passing the x coordinate, y coordinate, width, and height.
So far this is pretty boring. Luckily, it only takes a few tweaks for things to get a lot more interesting. Instead of passing the ellipse static values you can pass in things like 
mouseX
mouseY
, or 
random
. Passing in 
mouseX
 to the first value of
ellipse
and 
mouseY
 to the second value will make it so that you are essentially painting circles across the canvas wherever you move your mouse, because the ellipse will follow your cursor. If you pass random instead, the computer will generate a random number every frame and draw the ellipse to those coordinates.
You need to at least pass random a maximum number, so that it knows the range within which the random number can fall. If you want circles to cover the whole canvas, you can use 
random(width)
 for the x coordinate and 
random(height)
 for the y coordinate because P5JS stores the width and height of the canvas to those variables.
Also make sure you move background out of the draw function and into setup, otherwise you will only ever see 1 circle on the canvas because the background will continuously be drawn on top of it.
What the canvas will resemble when you pass in
random(width)
and
random(height)
.
Using mouseX and mouseY will be more like “painting” with the shape
Okay so now we’ve got lots of shapes on the canvas, but where is the COLOR?! Much like you can provide the background 3 values that reflect red, green, and blue you can do the same for shapes with the fill function. For example, if I pass 
fill(255, 0, 0)
 I will get a completely red circle like below.
But what if I pass random values instead? What do you think will happen?
Now we’re cooking with gas. Leandra went through similar steps in her live tutorial, to make sure everyone understood the basic principles and the most commonly used functions in P5JS. One of the most popular uses is to create visualizations that respond to sound. These are obviously a huge thing at raves and concerts, and they are easy and fun to make. The first step is to make sure you have the sound library linked in your P5 editor.
On line 5 in the above screenshot there is a url pointing to
p5.sound.min 
which is the P5JS sound library. If you click the little arrow above the code it expands to view the files that you see on the left hand side. Click on index.html and confirm that you also have the 
p5.sound.min
 script on line 5.
The next screenshot illustrates the additional code you will need in order to setup the mic and start receiving data from it that you can use for your visualization. Basically, you have to setup some variables at the top so that you can access your mic anywhere in the code. The variables start off empty but then you pass the actual mic in your setup function and start it so that it actually runs.
Finally, you need to get useful data from the mic so you call 
getLevel
 to get the loudness which you can use for visualizations. You can confirm that the mic is working by adding a console.log statement so you should see values being returned below your code when you run it.
I know that my mic is working because I am seeing values in my console at the bottom
We’re getting really close now. Only a few more steps to go before the finish line. Now that you know your mic is working, you can try passing in the
micLevel
and playing some music to see how the visualization responds. You can also introduce a few more functions, such as 
stroke
 and 
strokeWidth
.
The role of stroke is to define the color of the border of your shapes. Like fill, you pass in 3 values for red, green, and blue. On the other hand, strokeWidth is for defining the thickness of the border. You can see an example below integrated with 
micLevel
 for some cool effects.
We’re at the final step. It’s going to involve a slightly more complicated programming concept, so bear with me. This concept is called loops, and in particular we are going to use a for loop. Basically you define a variable, like num, and that variable can increase or decrease until you reach a specified stopping point. Most of the time, for loops are used to count upwards by 1 to a designated end point.
So a for loop like 
for(let num=1; num <= 8; num++) { console.log(num) }
 will output 
12345678
. Hopefully that makes sense. There is plenty of reading online about for loops if you are still confused.
Unfortunately it doesn't look that cool in a screenshot. It will look much cooler for you when you actually have the code in P5JS yourself and play some jams! So first, let me put the code here so you can actually copy and paste instead of manually typing everything out. This was the exact code that was written in the original P5JS tutorial.
<code style="border: 0px; font-family: monospace, serif; font-size: 15px; font-style: inherit; font-weight: inherit; margin: 0px; outline: 0px; padding: 0px; vertical-align: baseline; hyphens: none; line-height: 1.6;">
let mic;
let micLevel;
function setup() {
  createCanvas(400, 400);
  mic = new p5.AudioIn();
  mic.start();
}

function draw() {
  micLevel = mic.getLevel();
  background(5);
  
  stroke(255, round(micLevel * 800), round(micLevel*255));
  strokeWeight(micLevel * 200);

  
  for(let i =0; i &lt; 6; i++) { // for loop counting from 0 to 6 
    fill(random(250), random(100), random(255), 255); //1 circle is drawn with every loop, so 6 circles total
    
    ellipse(i*60 + 40, micLevel*5000 + random(50), 50); //micLevel for the y value caues the circles to go up and down with the volume, i*60 means a new circle is drawn every 60 pixels along the x axis
  }
 
}
</code>
Hope you enjoyed this P5JS tutorial. I also tweeted out a video of my own code and music so if you don’t feel like it or don’t have time right now to tinker with the code here is a short video. Make sure you turn the sound on!
If you enjoyed this article, consider following me on Twitter @nadyaprimak or if you need more tips on breaking into the tech industry, you can read my book “Foot in the Door”  in paperback or Kindle now.

Written by nadya-primak | Software Engineer and Indie Game Developer. Creative Technologist.
Published by HackerNoon on 2020/04/17