JavaScript 🎵 Audio 🎵 Visualizers

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
html canvas offers two built-in methods to draw curves what's the difference between them it's simple quadratic curve two method allows us to draw one curve we set starting point with move to method the first set of coordinates passed here is a control point and the second set of coordinates is the end point bezier curve 2 allows us to specify two curves again move 2 is the starting point and then we pass it control point 1 control point 2 and the end point let's use it in a project sharing is caring so in this creative coding crash course i will share all the tips tricks and techniques you need to create your own audio visualizers in this particular style we will build two animated creatures together that react to voice and music from start to finish in a single video this is a crash course i will go faster especially over the easy parts such as html and css setup and so on if you want more detailed explanations check out my web audio api deep dive linked in the description we built a lot of different cool visualizers and audio effects in there as well if you are a beginner maybe it's a good idea to start with a complete javascript course at first understanding the basics will make it much easier to follow project tutorials like this one if you are interested i will link some recommended udemy courses in the video description let's create a basic webpage markup i'm not sure if you know but you can use these special unicode emojis on the web even with the page title since we are building audiovisualizer i will pick something with a music theme and now you can see it here i'll install css file i create canvas element with an id of canvas one and i link my javascript with script.js file like this i drew snail in adobe illustrator and exported it as a simple svg svg stands for scalable vector graphics the special thing about svg is that they always look sharp and because it's not pixels it's just cold we can make them larger and the parts are just redrawn it will never look blurry as switches are always sharp no matter how large we make them you can grab this code somewhere in the video description i can give svg styling using normal html style tag like i'm doing here i'm creating a special linear gradient element inside my svg tag that defines color stops and individual colors i'm giving that gradient id here and applying it through style tags here to my snail shape i'm also setting stroke width to 2 pixels in star css i just do global reset to make sure we don't get different margins in different browsers i give my body black background and i set overflow to hidden to hide potential scroll bars svg element with an id of snail will be centered so position absolute top fifty percent left fifty percent transform translate minus fifty percent minus fifty percent i give it a set width of 800 pixels and i give it a set index of -1 because i want to make sure it's always behind my transparent canvas element i target all paths inside the svg image and i will play with their stroke css property called stroke dash array defines the number of slices that make up outline of each path stroke dash offset can be used to push that path around my path is made out of 1500 segments and i pushed it by hundred five hundred one thousand or one thousand five hundred stroke dash offset is easy to animate but first let's give the snail a shell in script.js i want to make sure everything is fully loaded before running javascript so event listener followed event and i console lock test perfect canvas setup i gave my canvas id of canvas one context is canvas get context 2d i also need a reference to snail element i make canvas blue just so i can see if everything is working canvas width is window in the width canvas height is window in a height great i can make my canvas transparent again snail shell will be made out of animated audio bars so i create a class called bar it will need x y width height color and index arguments to come from the outside and i set them up like this as we always do inside class constructor update method will animate bar height based on incoming mic input value draw method will take context and volume as arguments and it will take that canvas and draw rectangle on it representing the audio bar nice we need animation loop first clear rectangle to clear old paint we only want to see the current animation frame some code in between and then i use request animation frame and i pass it animate to create an endless animation loop i call animate and i put some console log here just to check that the animation loop is running success i use bar class from line 8 to create one bar element i pass it x y width height color and index and i call its draw method from line 20. it expects context and volume so i pass it ctx and the one as volume for now i can't see it yet because the default fill style is black i set fill style to this dot color which i set to orange red on line 25 i can check if everything is working by animating for example x horizontal coordinate and height properties so far we are doing great let's delete that now i need to bring live microphone data into the project i create a class called microphone constructor will take fft size as an argument fft size stands for fast fourier transform algorithm which is used by web audio api to slice raw stream data into a specific amount of audio samples it takes a fraction of a second for microphone to initialize and i need to wait for that so at first i set this dot initialized to false i will use built-in web audio api that now finally works in all major browsers and is well supported we will use it to bring audio data into our project transform it and analyze it if you feel like i'm going too fast today there is also a deep dive version of this tutorial where i built slightly different visualizer using the same techniques but it's based for beginners and i explain every built-in method and technique in detail i will link the deep dive version in the video description navigator navigatorobject.mediadevices and i can call getusermedia i tell it i want incoming audio data from microphone and i wait for that javascript promise to be fulfilled i chain then method and inside we will handle a stream of raw audio data coming from microphone i bring web audio api into the project by calling new audio context this gives me access to all its built-in properties and methods from this dot audio context variable it has so many useful features that allow us to slice mix transform and create audio i need to convert raw microphone data into an audio source i do it by calling built in create media stream source method and passing it that raw stream data now it's saved in this.microphone variable i will also need analyzer node built in create analyzer method creates this special analyzer node that when connected to audio source will expose its time and frequency data we need for creating visualizations analyzer node has fft size property fast fourier transform algorithm will slice data into specific number of audio samples it can only be certain values we will use buffer length just so we know how many audio samples we are getting frequency bin count property is always exactly half of fft size value now i want to create a new unassigned 8-bit array with a specific number of elements number of these elements will match the number of available audio samples i take this microphone which is my audio source as we set it up on line 32 and i connect it to analyzer node to slice it into samples and expose its time and frequency data and that's it i can set this dot initialized from line 28 to true if the promise doesn't bring audio and it gets rejected i call catch method and i just display the error it gives me as an alert i need a public method i can call that will give me current audio samples coming from the microphone as an array i take analyzer node and i call its get byte time domain data method which takes current waveform and it will fill it into data array from line 36 it will override it with new incoming audio data i want to normalize my audio samples right now data array has elements with values between 0 and 255 i want to convert them into a range of minus 1 and plus 1. i convert data array from unassigned 8-bit array into a regular array i call map array method and i divide each element by 128. since each element is a value between 0 and 255 divided by 128 will give me values between 0 and 2. and when i do -1 i push the range into values between -1 and plus 1. then we can return a normalized samples array i also need getvolume method which will calculate average of all audio samples and gives it to me as a single number i copy the same two lines we just wrote i create a summer variable that will accumulate value of all audio samples since these values have range between -1 and plus 1 to get their average i need to use root mean square i cycle through normalized samples array and i square each element and i add it to total sum value this will move all values into positive since minus times minus is plus to get my average volume i can just get square root from sum divided by number of samples like this and i return volume this could have also been done much simpler without root mean square i think next time microphone setup is complete we try to get microphone data if it's successful we set up our microphone class if the promise is rejected we show error message we have public method to get audio samples as an array of values between -1 and plus 1 and we have another method to give us the current volume as a single value i create an instance of microphone class on line 27 i see it needs to be a specific value for my snail effect i will use 512. in animation loop i will wait until microphone initialize this true and i consolate microphone i can see my microphone object in the console i put clear rectangle inside this code block i set fft size as a variable and i pass it in like this i create empty bars array that will hold all audiobar objects as we said the number of audio samples is always half of fft size value so if i want bars to spread across screen bar width will be canvas width divided by fft size divided by 2. brackets are important here inside create bars function we run a loop for each audio sample and we take bars array and we push bar object inside on line 9 i can see bar class expects arguments for x y width height color and index x will be 0 y will be 0 color is right index is i from the for loop actually width will be bar width vertical position 200 pixels and horizontal position bar width times i to spread them from left to right across the screen now i can call create bars and i console log bars array just to check perfect we set fft size to 512 and we have 256 bars representing 256 audio samples in the array inside animation loop i will call for each on bars array i will call each element for example bar and i also want to pass it optional index variable like this i call draw method from line 20 and i see it expects context and volume so i pass it ctx and volume 1 for now i can pass a different vertical position also different height 150 pixels 250 bars react to their current height great width can also be 1 pixel or 0.5 let's use git samples method from line 43 and use it to give us an array of values representing current audio data coming from microphone we can then animate height of each bar based on these values constant variable called samples is microphone dot get samples i get an error probably you already noticed my typo somewhere let's see i spelt initialized differently on line 38 let's fix that and this is wrong of course i need to do comparison operator so that we actually wait for microphone to be fully initialized nice now it works let's console examples yes we are getting audio from the microphone how do we connect it to animation it's simple as i said before this is a speed coding version i also made a deep dive project tutorial on this topic if you want more explanations about how all these methods and techniques work let's animate it on line 17 we can see that update method expects mic input data to animate height i call it here and i pass it samples with that particular index these samples are very small values between minus one and plus one so you can't actually see it i will multiply it times one thousand awesome we are animating microphone audio for the rest of the episode i will be playing music into my microphone so that i get constant movement i will also edit that music out so that it doesn't distract you it's moving very fast what if i want some ease in and animation here i create a constant variable called sound and i set it to mic input times 1000 if sound is more than height instantly set height to match that value else slowly decrease height to create animation also i need to delete that okay let's make it into a spiral to give our snail nice animated shell i set line width to this dot width from line 12 i call built in save and restore canvas methods so that i can do some translates and rotates in between wrapping any canvas settings between save and restore will make sure these properties don't affect other elements outside restore will reset everything to the state it was at the last save point i can for example rotate and as rotation angle i pass it index that way each bar will have different rotation i put rectangle inside i replace rectangle with lines move 2 will set starting coordinates of the line line 2 will set ending coordinates i call stroke to actually draw the line i delete this console log i can change rotation line width doesn't do much now i comment it out even smaller rotation i translate rotation center point from coordinates 0 0 to the middle of canvas oh i also need to call begin path when drawing a line otherwise everything will be one very long shape this probably made your computer lack if you are coding with me i adjust values i pass to move to method i change rotation line width is this dot width i can play with rotation to get very different shapes okay lines work well let's try busier curves built in canvas bezier curve 2 method takes three sets of coordinates these coordinates are not the exact positions of the line they are so called control points which the line curves towards now i want to somehow curve them to create a snail shell shape i change rotation adjust these values interesting i really like these shapes if you are coding along you can see it's really cool how precisely it reacts to your voice and music i realize the red color might be blended with back background on some screens i will change it in a minute here on line 78 i adjust initial x coordinate i pass to my audiobar objects nice circular visualizer passing it index as a vertical coordinate will make it into a spiral shape with 1 pixel height doesn't do anything as it's been overwritten immediately by incoming audio values i can adjust the size by changing y-coordinate here i don't really know why the first bar doesn't animate and stays this long it's a bit strange if you know why it's doing that let me know in the comments please looks like update method is skipping the first element for some reason i will fix it in a minute first let's make the snail image pulse with volume i wrap this code in save and restore i translate rotation center point to the middle of canvas i remove this other translate call completely as translates are additive better rotation nice i can position the shell in relation to snail by hard-coding some values here it should be responsive and work on different screen sizes even when i hardcore values because both visualizer and snail are centered in the middle and snail has a set width if it wasn't centered i would have to offset it by relative values here that consider page size and size of the graphics i will fix this first long bar that's not animated properly by starting my index at value 1 instead of 0. let's give it more colors let variable called color will be hsl color declaration you will be equal to index from the for loop it will make it cycle through the color spectrum saturation always hundred percent lightness always 50 and instead of passing it red i pass it this dynamic color variable i can change how fast we cycle through color spectrum here i can also push it along the spectrum since u0 is red by pushing it like this we start from a different color i bring volume into the project by calling getvolume method we wrote earlier i pass volume to my draw method actually maybe i will use volume in animation loop directly to make the snail svg image move i already have a variable pointing towards the image up on line 4. i take that variable and i set its style dot transform to translate minus 50 minus 50 since we are already doing that with css to center it in the middle of the page i need to replicate that here and i can add dynamic scale it takes two arguments for horizontal and vertical scale i will soften the volume values so they are not as jumpy first i declare soft volume outside and then for every animation frame i assign soft volume to soft volume times 0.9 plus the actual volume coming from get volume method times 0.1 this will smooth out transition between volume levels and it will make animations attach the volume value less jumpy first i add raw volume coming directly from the microphone to horizontal and vertical scale just so we can see the difference it's too much i need to wrap the values in brackets like this i can also multiply the volume here you can see how the snail pulses as it reacts to sound if i replace volume with soft volume we just create it you can see the transitions are smoother i think it looks better like this let's add more shapes to the visualizer i want to create a circle but only for a portion of the elements so if this.index is more than 100 only then draw a circle position will be this dot x and this dot y plus height to position them on the outer radius of the shell size will also be dynamic maybe this dot height times 0.5 start angle 0 and angle math.pi times 2 and we stroke it they are not rotated because restore was called which removed all translates and rotates i move restore here and now my circles are rotated around the shell also i need to replace ctx with context i can change the size feel free to play with the code and do your own experiments if you are coding along i will also draw a line between shell and each circle so begin path move two from these coordinates line to these coordinates and i stroke the path interesting i think this looks really cool i can change the power of audio coming from microphone here on line 18. i can give it some spacing in between for example and maybe also some margin here nice more audio power maybe more scaling as well if you could hear the music you would see it reacts really well i like it stroke dash array defines a number of segments we want in svg path let's animate it i call it animate path for example three break points zero fifty and hundred percent we start from one thousand five hundred and twenty and we go to zero and back to one thousand five hundred and twenty now i attach this keyframes animation to all my paths here animation animate path i want it to run every 5 seconds infinitely i actually meant to type stroke dash offset on each breakpoint like this we can make it cycle between different offset values even negative to draw the shape in different ways i can also give it some ease in here how about these values nice i think it's clear how it works stroke dash array defines what portion of the outline we want to show and stroke dash offset defines how much we want to push it in a certain direction svgs are lightweight they are much smaller than regular images because it's just cold defining outlines they are also always pixel sharp no matter how much you zoom in on them and they give us access to many cool effects such as this path animation i can limit how many lines and circles i want to draw here i only want them to be on top of the shell when i resize window it breaks i can fix it easily with event listener for a resize event and in call back i just set canvas width to window in width and canvas height to window in a height let's do one more you can take my svg drawing code in the video description in index.html i replace snail with a seahorse it's a bit more cold since the seahorse is made out of more lines i need to adjust these css selectors i make it smaller by giving it width of 300 pixels i can see it's not outlining the entire shape which means we need a higher value in a stroke dash array i temporarily disable animation i can just break the name like this for a moment to make it stop animating svg path i need a higher value here to get the whole shape let's see how much until i get all of it nice now i can adjust animation range here i enable animation again by adjusting these values we can change what portion of the shape is being animated in script.js i need to fix this variable and id on line 4. down here on line 110 i also replace the variable name and we get scale effect that reacts to volume again i make it move a bit less let's turn this snail shell visualizer into a ridge that comes from seahorse's back i think it could look really cool while seahorses have all kinds of crests running along their backs i adjust rotation on line 29 i delete this entire code block that was to draw in lines and circles i can position the entire visualizer by translating and rotating it here let's try to rotate by -2 radians maybe a bit more i can position it here inside translate call as we said in the beginning the start point of bezier curve is defined by move move2 method let's start from these coordinates the first control point can go for example in this direction now i do something about the second control point the second curve and i also adjust ending x and y coordinates of the curve you can play with these values yourself to see what shapes you get i can tweak it a bit this looks nice i want a circle at the end of each line i use arc method and since i want the center of the circle at the tip of each line i pass it these ending coordinates i pass it some radius start angle 0 and angle math.pi times too i can fill it fills it with the default black color i set fill style to this dot color and we can see the circles if you are getting performance issues you can reduce fft size on line 80. it will change the entire shape so another way is for example to only draw every second bar if this dot index modulus 2 is a 0 this is so called remainder operator modulus if index value of this bar object is divisible by 2 with a remainder of 0 only then we draw it the more shapes you draw on canvas the more performance you need my computer is having absolutely no issues now and i'm also running screen recording software this is just for people who code along on old computer this is meant to be context let's create another layer of lines begin path move two starting coordinates from here line two and then coordinates may be here and i stroke it nice if i comment out line 32 you will see what we just did again maybe i don't want to draw so many lines maybe just every third line i can adjust direction of the lines by changing multipliers on x and y coordinates congratulations if you followed this far let me know in the comments if you did you can just say i did it if you are still feeling creative check out my playlists i will link some related videos in the description down below i will see you there
Info
Channel: Franks laboratory
Views: 47,175
Rating: undefined out of 5
Keywords: Audio Animations, web audio API, javascript audio, audio visualiser, audio visualizer, JavaScript Tutorial, javascript for beginners, learn javascript for beginners, JavaScript audio, learn JavaScript, javascript visualization, javascript visualizers, audio visualization, audio visualizers, javascript, html canvas, html5 canvas, html5, css3, creative coding, franks laboratory, frankslaboratory, javascript audio visualizers
Id: Ub70TitG6_k
Channel Id: undefined
Length: 28min 17sec (1697 seconds)
Published: Sat Nov 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.