Audio Magic with JavaScript

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] the web audio api is a powerful and versatile system for controlling audio on the web it has a set of built-in methods and properties that allow us to generate play and analyze sounds directly in the browser today we will show you how to use html css and javascript to animate your voice and the music let's do some audio magic together and learn about front-end web development in the process this tutorial is for beginners so feel free to code along [Music] i love javascript there are so many different things you can do with it in this course we will learn how to easily get audio data from microphone using just plain vanilla javascript no frameworks and no libraries we will analyze that data and connect it to animated visualizers i will show you how to create a set of rainbow effects and then we will join radu to create a talking pumpkin character we also made another course using similar techniques where i connect 12 very different visualizers to locally stored audio files and radu teaches how to generate sound with javascript i will link all related courses in the video description let's have fun with code and become better front and web developers in the process click like if you get any value [Music] [Applause] [Music] project will consist of five separate files in index.html i link style css file and i will also link three separate javascript files since i'm including them in this way the order is very important make sure microphone is the first one so that the code inside is available for visualizer and pumpkin javascript files both of them will use microphone data in a different way to create really cool audio animations we don't have to include the javascript files by using multiple script tags like this alternative solution is to use the javascript modules with import export keywords but keep in mind for javascript modules to work you need to open your project through a server in some kind of dev environment i want to keep it simple today without explaining how to run a local server so let's just use multiple script docs like this in microphone js i will show you how to use vanilla javascript to get audio data coming live from your microphone in visualizer.js we will use it to create all different kinds of animations that react to your voice and music in pumpkin.js radio will show you how to draw a character that moves the sound i create a canvas element with an id of my canvas and i want to make sure the page is fully loaded before running javascript so i will create inline unload event inside body element like this we will run a function i call for example main we will declare it in a minute in style css i do global reset to make sure our page appears the same across different browsers and i will give my canvas black background that's it everything else will be done with the javascript let's jump to visualizer.js file to set up our canvas and draw something first i need to create a function called main inside i will just console load it i attached that function to unload event on body element in index html on line 13. let's check if it runs by opening browser console yes i can see the message here perfect inside main function i set up my canvas constant variable called canvas is document.getelementbyid mycanvas ctx context is canvas variable from line2 dot getcontext and i pass it 2d to specify i need access to all built-in canvas 2d drawing methods and properties i make sure my canvas covers the entire browser window so canvas width is window in width and canvas height is window in height we need to do this to make sure we have the correct scaling this gave me scroll bars in browser window to get rid of them i go to style css i take my body element and i set its overflow property to hidden my audio visualizer will be made up of bars each bar will react to values coming from microphone and it will have some properties and special animations so i will use javascript class to create them javascript classes are great if you want to create many similar objects in this case many bars that will make up our audio visualizer it will have constructor method which is mandatory for all classes it will have a custom update method that will handle microphone data and it will calculate positions and sizes and also it will have a custom draw method that will just take the data and give it shapes and colors finally we need animation loop that will call update and draw methods on all my bar objects over and over so we get an endless loop that takes microphone data analyzes and transforms it and makes shapes and animations from it first i will call built-in clear rectangle method to clear old paint from the previous frame i want to clear the entire canvas from coordinates 0 0 to coordinates canvas width and canvas height then we will have some code that generates audio samples from a microphone it's easy don't worry i'll explain it so that even beginners can follow then we will animate bars based on that microphone data and we will use built-in request animation frame function and we pass it animate to create endless animation loop to start the loop i need to call it like this i will give it console log that says animate just to check if our code is working so far in console log i can see we have scope issues animate function from line 18 can't see my ctx variable on line 3 which is inside main function i can easily fix that by placing my bar class and animate inside main function like this now i can see the console lock is being called over and over great we have a running animation loop let's delete the console lock as they can be a major source of luck when called for every animation frame like this constructor is a special mandatory method on javascript class that serves as a blueprint it runs when we call the class with the new keyword and it will create one new blank object and it will give it values and properties as we declare in here inside the blueprint all our objects created by bar class will have the same properties such as x and y position but their values on these properties can be different for example every bar can have different x and y position different size and so on that's why we say javascript classes are used to create many similar objects my constructor will expect 5 values to come from the outside for x and y coordinates with height and color we will pass them to the constructor when we call our class with the new keyword in a minute inside i just created these properties this dot x x property on this new blank audiobar object we are creating right now is equal to x that was passed as an argument here on line 8. i do the same for vertical y-coordinate width height and color update method will be responsible for updating these properties based on audio input coming from the microphone so we pass it mic input variable as an argument and here i can for example say this dot x horizontal x coordinate is equal to mic input or maybe height of the bars will be equal to mic input we will experiment with this later when we have some animation going so you can see exactly what's going on we will also have a public draw method here this custom draw method will take x y with height and color properties from this bar object and it will draw some shapes based on these values i will pass it ctx as an argument to make sure we are not using global variables directly inside the class actually let's name it context to make it clear what's going on i will explain it when we get to the point where we call this draw method from inside animation loop let's start by drawing a rectangle to represent this audio bar i use built-in fill rectangle method and i pass it this dot x from 99 this dot y this dot width and this dot height from line 12. by default fill style is black and we have black background so i will set fill style to this dot color from line 13. i will show you how to pass that color to the class right now now that i have my bar class i can use it i create a constant variable called bar 1 and i set it to new bar like this the new keyword will look for bar class and it will trigger class constructor on line 8. i can see it expects 5 arguments so i pass it 10 10 for x and y 100 for width 200 height and blue color bar 1 was created by instantiating my bar class from line 7 so it has access to its public update and draw methods i can call them like this bar 1 dot draw on line 18 i can see that draw method expects context as an argument so i pass it ctx from line 3. i take ctx variable here on line 3 i pass it to the draw method on line 26 inside the draw method we refer to that ctx variable as context and we call all drawing methods on it doing this is a good practice yes i could have just taken ctx from line 3 and used it directly in my draw method but pulling global variables directly into our classes is a bad practice the right way of doing this is to pass global variables as arguments to our public methods the way i'm passing ctx to draw here on line 26 also maybe for some reason i could have another canvas and i want bar 2 to be drawn on that second canvas instead with this syntax is easy i will just pass it a different argument and my draw method will draw it on the other canvas if i have one it's useful especially for projects where you have multiple layers just to check our update method is working correctly let's just say increase this.x from line 9 by 1 for every update call and on line 27 inside animation loop i call bar 1 update perfect we can see that our update and draw methods work i'm creating one bar here on line 24 using my custom bar class i will delete update for now we don't really need just one bar we need a lot of bars each representing one audio sample coming from microphone input let me show you how easy it is to get live microphone data and animated for this to work you need to have a microphone device available on your computer if you have a macbook or laptop you are fine because they always have built-in microphones if you are on a desktop computer probably you will need to plug in external mic on windows computer you can open device manager and inside sound video and game controllers you will see if you have any microphone hardware available we will write code that brings handles and transforms microphone data in a separate file this file is compatible with the second part where radu creates a token pumpkin character in this video we will use it to create some awesome audio visualizers in my index html i need to include the files in a specific order microphone needs to come first so that it's available for our audio visualizers and talk in pumpkin in microphone js i create a new custom class i call for example microphone i give it a constructor let's create a custom property called this dot initialized because we want to wait until we start receiving sound data before we start animating i will set initialized to true as soon as audio data starts coming so how do we get microphone data in browser it's actually quite simple let's do it step by step and explain everything to make sure we know what's going on navigator.mediadevices is a read-only property that returns a built-in media devices object which provides access to connected media input devices such as cameras microphones and screen sharing then i call getusermedia built-in method this special method returns a promise that resolves in a media stream object which contains microphone audio data some browsers will give you a prompt where you have to click ok that you agree to use your microphone this get user media method expects some parameters we call them constraints where we have to describe what type of media we are looking for we have options to choose audio video or both i will choose audio by saying audio true like this i said that get user media returns a promise promise is a special javascript object that represents eventual completion of asynchronous operation we use promises when we want to wait for something to complete before we run some follow-up code in this case we want to wait for audio data to start coming from microphone before we continue setting up our microphone class promises can be fulfilled or rejected we can also chain multiple promises using built in then method where each chain promise waits for the previous one to complete before it runs its code we can also set up different actions based on whether the promise is fulfilled or rejected so getusermedia returns a promise we wait for that promise to be fulfilled and microphone audio data to start coming we chain another promise using built-in then method if get user media promise is fulfilled we will receive a built-in media stream object that consists of audio track data i will call it for example stream so now if the promise was successfully fulfilled and we have microphone data coming i can chain a follow-up promise using then method and i can finish my microphone class blueprint by giving my class some additional properties we will need audio context property and i set it equal to new audio context like this this is also very important every modern browser has access to built-in web audio api it's basically a set of methods and properties that allow us to generate play and analyze audio and you can do a lot of sound and animation magic with it it's basically very similar to canvas api but canvas is for web graphics web audio api is for sounds this is how you bring web audio api to your project and now i have access to all its built-in methods and properties from this dot audio context variable these methods are very powerful and they allow us to process and synthesize audio directly inside browser we can do mixing processing and filtering tasks on sound and i can make many videos about this building different effects today we are learning the basics to make sure we understand it and by the end of this course we will create something nice with what we learned now i need to convert the raw stream data returned by get user media into audio node format that i can use for my animations i will store this data as this.microphone property for example as i said i can use this.audio context to call all built-in web audio api methods i will use built-in create media stream source method that takes raw media stream in this case raw audio data coming from microphone and it converts it into audio nodes we convert it into audio notes because that's the format web audio api can work with think of audio notes as base building blocks for managing sound in browser audio nodes can be analyzed i need to do that to convert them into nice visualizer animations i create another custom property on my microphone class called this dot analyzer then i take this.audio context and i call another useful web audio api method called create analyzer the job of this method is to create so-called analyzer node which can be used to expose audio time and frequency data to create visualizations this analyzer node has certain properties the most important property is fft size it stands for fast fourier transform algorithm in this case it will help us to slice the audio into an equal number of samples you can't just give it any number it must be a power of 2 between 2 to the power of 5 and 2 to the power of 15 so 32 64 128 256 512 and so on if we don't declare this value it will default to 2048. these audio samples can also be referred to as bins i need to know how many of these bins i have available i create a variable called buffer length and i set it to this dot analyzer dot frequency bin count frequency bin count is read only property and it's always equal to half of fft size value if i have fft size set to 512 frequency bin count is half so 256 and my audio visualizer will have 256 animated bars to make this audio data easier to manage i need to convert this buffer length into a special type of 8-bit array i created this data array property and i set it to new uint8 array and i pass it buffer length i do this to convert my audio data into an array of unassigned 8-bit integers these integers can only be whole numbers between 0 and 255. so this new data array will contain 256 audio samples coming from microphone and each of these audio samples will be represented by a value between 0 and 255. now i take this.microphone from line 7 and i use built-in connect method of web audio api which allows us to direct data from one audio node to another i direct my audio stream data coming from microphone into the analyzer node we created i'm collecting microphone data converting it to a suitable format creating analyzer node setting it up and feeding my microphone data into analyzer node so that it's ready to be used for audio visualizations once we do all of this we set this.initialized to true it might seem like there is a lot going on here but if you use these steps a couple of times and become a bit more familiar with it you will realize it's actually simple the same technique can be used for analyzing audio files stored direct on your computer for example if you want your visualizers to move to your favorite mp3 files i have another video where i explained that and i also built 10 very different unique visualizers there i'll link it in the description we are still inside a javascript promise returned by getusermedia method if the promise is successfully fulfilled this block of code will run and we are getting microphone audio data if the promise is rejected for some reason for example if user clicks no when browser asks for permission to access microphone our promise will be rejected for that we can chain another special method called catch catch method deals with rejected promises and it has auto-generated error message argument all i will do here is create alert that will show us the error message like this so we are asking for access to microphone audio getusermedia returns a promise if we are successful then a method is run and our microphone class is set up and if it's rejected we get an error message i can instantiate my microphone class by creating a custom variable called for example microphone and i set it the new microphone like this we get an error that says cannot set properties of undefined by the time this asynchronous then call is executed javascript forgot what this keyword represents to prevent that from happening i need to use built-in bind method i need to chain it right after the then call bind method is very simple it just tells this then method to set its this keyword to the provided value it says don't forget that when we call you a bit later when the promise is fulfilled this keyword refers to this microphone object i can console microphone object from line 19 just to check the properties on it here i can see its analyzer property we declared on line 8. it has fft size set to 512 and its bin count number of its audio samples is 256 exactly half of that as expected perfect if i set fft size to 1024 our media stream coming from microphone will be separated into 512 slices it's always exactly half our custom microphone class will have two public methods get samples that returns an array of audio samples for visualizers and get volume that will return a single average value of current audio volume coming from the microphone get samples method will give us audio samples array coming from the microphone we'll call it over and over from animate loop getting new microphone data for every animation frame and using it to update our visualizers i take this dot analyzer property from line 8 and i call get byte time domain data this special method copies the current waveform or time domain data into an array we passed to it so i pass it this.dataarray from line 11. it will basically overwrite whatever is in that array at the moment with new audio information now my data array on line 11 contains current audio values coming from the microphone it's a special type of array called uint8 array it can only hold elements that are 8-bit unassigned integers between values of 0 and 255 let's say i just called get samples it will give me this data array of 256 elements where each element is an integer between 0 and 255 and all of them together represent audio wave data coming from microphone at that point in time we can work with that already but sometimes it's easier to convert it to a more suitable range of values i want to normalize my samples and spread them between the range of minus 1 and plus 1 which will serve us better in our visualization i create a variable called normalized samples first i want to convert it to a regular array so that i can use built-in arraymap method on it there are many ways to convert something into a regular array for example i can set it equal to array literal like this this will create an empty javascript array on the fly then i put this.data array from 911 inside and i write three dots in front of it like this this is so called spread operator that will take data array from line 11 and it will spread it into this new array literal i just created i do it to convert this unassigned 8-bit integer array into a regular type of array so that i can call built-in array map method map method will allow me to perform operation on each element in the array we know that each element is an integer between 0 and 255. i will call each element for example e and i tell my map method to divide each element by 128 minus 1. this line of code just took array of elements where each value is between 0 and 255 and it converted each one into a value between -1 and plus 1. i know this calculation is very hard to read for most of us as we said these elements are values between 0 and 255 so dividing them by 128 will give us a set of values between 0 and 2 like you can see with some of these examples so this part gives me values between zero and two and if we adjust them by minus one we get a range between minus one and plus one this calculation is complicated math and don't worry if you can't fully visualize it your ability to understand calculations and math like this has nothing to do with your ability to be good with javascript all you need to understand here is that our git samples method will take audio data which was originally saved as an array of values between 0 and 255 and it converts it to an array of values between -1 and plus 1. then it returns this normalized array in a format that is ready for animation nice as i said before this normalized calculation is optional we could also animate the original values between 0 and 255 directly so don't worry about this calculation on line 20 too much i will also create another method called get volume the job of this method is to give us a single value that represents overall current value of audio coming from the microphone i will do the same thing i just did inside getsamples so i copy these lines of code and i have an array of normalized sample values between -1 and plus 1. i will create a helper variable called sum which will hold a total value of all my audio samples here i want to get average volume value from all 256 audio samples in a normalized samples array normalized samples represent a wave they are in a range between -1 and plus 1. it's a wave centered around 0. if they were all positive numbers i could simply calculate average here when we have data in a wave on both positive and negative side from 0 we use root mean square to get their average we start by squaring each value each value will be multiplied by itself so even the negative values will end up as positive numbers because minus one times minus one is plus one as we cycle through the array with for loop we are adding these values to the total sum i do that for each element in normalized samples array so by the end my sum variable has accumulated all the values into a single number i get average from it by square rooting sum divided by total number of elements so my get volume function takes audio data from microphone converts them into a range of -1 and plus 1. it creates a total sum of current values and creates average volume value from it then it returns it our microphone class is complete it takes audio data from microphone it gives us option to get these audio samples as an array of values using public getsamples method or we can get a total volume as a single number with getvolume method we have everything we need let's use that microphone data to create animations in visualizer.js file in index html i'm including microphone js then the visualizers so in visualizer.js microphone class we just wrote is available i go to line 25 here and i will instantiate microphone class by saying const microphone equals the new microphone if i consult microphone we can see our custom object with all the values and properties as we just defined in microphone js file nice on line 24 i'm using my bar class to create a single blue rectangle let's delete that i also delete this draw call i create a custom function called for example create bars its job will be to call bar class from line 7 and create one audio bar object for each audio sample comment from microphone inside create bars function i create a for loop that will run 256 times on my microphone class i set fft size to 512 and we know that gives us 256 audio sample slices exactly half so this for loop will run 256 times i will need an array to hold my bar objects i created here on line 25 inside the for loop i take bars array i just created and i call built-in push method on it push method takes whatever we pass to it as an argument and pushes that to the end of the array i will pass it new bar on line 8 i can see my bar class constructor expects 5 arguments so i pass it index from the for loop as x i pass it 0 as y 10 pixels width 100 pixels height and a gold color let's control bars array from line 25 it's still empty i need to call create bars function to fill it with objects like this now i can see my bars array contains 256 objects created using our custom bar class you can see how horizontal x coordinate increases by 1 as this for loop runs from 0 to 256 because i'm passing this i index as horizontal x property to the class constructor each of these bar objects inside bars array was created using our custom bar class which means they all have access to update method from line 14 and draw method from line 19. i take bars array from line 25 and i call for each array method this method will simply take each element in the array one by one and do something with them i will specify what i want to be done with these elements inside a callback function here all i want for each bar is to call their associated draw method for now you can see how they move from left to right as their horizontal x-coordinate increases from 1 to 256 depending on index their position in the array what happens if i also set vertical y-coordinate to this index interesting we get both x and y increasing by 1 for each bar here i set bar width to 10 pixels what if i want bars to have specific width to cover my browser window from left to right horizontally i can create a variable called bar width and it will be width of canvas divided by number of bars 256 in my case so horizontal x-coordinate will be index of that bar times bar width and now they spread across screen i can change their width to 1 pixel if i want some space between them for example i can move the entire row vertically by adjusting y coordinate value here for example i want them to start 10 pixels from the top or maybe in the middle of canvas canvas height divided by 2. i can also change height of the bars by passing different argument for height to my bar class constructor what if i want dynamic colors instead of hardcoding gold color for old bars we can use hsl color declaration hue saturation and lightness custom helper variable called for example color and i pass that variable here to my bar class the way hsl color works we pass it hue saturation and lightness i will keep saturation always 100 percent i always want full colors i will always keep lightness on 50 0 lightness is black 100 lightness is white 50 is original color not affected by light or dark at all we can travel through the entire color spectrum by adjusting just this one value representing hue the way it works is that this u value represents angle on hsl color wheel 0 degrees is red 60 degrees is yellow 120 degrees is green 240 degrees is blue 360 degrees circles back to red and the more you increase hue value it will just circle around over and over so one circle is 360 degrees that's why hue 720 will be red again because it's 360 times two we just made it circle two times around the color wheel because of this behavior we can increase hue to higher and higher numbers and our effects will endlessly cycle through the color spectrum i can replace hue with a variable to make my colors dynamic i could for example use index from the for loop as a hue value we start at index 0 red color the for loop starts and as it increases we travel through the color spectrum i can also multiply it times 2 to make the colors change faster nice so here we use create bars function to create 256 bar objects and we pass them position and color values to spread them across the screen it's time to take microphone data and make our bars move to sound coming from a microphone i do that by calling update method we wrote it here on line 15 and we can see it expects mic input as an argument i delete this line and i set height of each bar to change depending on incoming mic input value so i pass it 100 as input we get bars with 100 pixels height or one pixel height you can see bar height reacts to the value we passed here so let's feed it audio samples coming from microphone instead i create a constant variable called samples and i set it to microphone from line 23 dot get samples we wrote this method on our custom microphone class inside microphone js earlier i get a console error that says cannot read properties of undefined it is because it takes a fraction of a second for get user media online 4 in microphone js file to fulfill a promise and start bringing microphone audio data so we need to wait for that by checking if microphone initialized is true if we don't wait we get undefined error and javascript will stop so wait in until initialized property on microphone is true will prevent this error from happening when microphone is initialized only then we will run all this code at that point audio samples are available and controlling samples on line 40 i can see that samples are coming in perfect if i open the samples you can see each samples array is a set of 256 values between -1 and plus 1. let's remove console log from line 40. for each array method has automatic index argument as for each cycles through the elements in our case from 0 to 256 i need to assign it a variable name like this i call it for example i javascript will automatically know that this value represents each individual element and optional second value represents index this is how for each array method works in javascript so now i have index for each element and i can pass it to update method as input and we will get increase in length of bars with height from 0 to 256 pixels we don't really want to do this here i just tested that index works and now we can pull appropriate value for each bar from samples array from line 39 i do it by passing each bar samples index i like this we have samples array coming from microphone which has 256 audio samples and i'm assigning each one to one of my 256 bar objects to pair them up this will be happening over and over for each animation frame so on most computers 60 times per second we are asking microphone to give us this samples array and we are using these values as argument to pass to update method on custom bar class from line 15. we refer to the samples value as mic input and we know these are very small values between minus 1 and plus 1 so we don't actually see much on canvas let's multiply them by 20 or maybe a thousand success we are pulling microphone data and animating it on canvas congratulations if you followed this far the rest of this course will be just fun experiments and drawing the data in more interesting ways using html canvas let's do some creative coding experiments which is always my favorite part what i will do now i will play music you can't hear it because i will be editing it out i don't want you to be distracted but i will play music into my microphone for the rest of this video so that we get some emotion and animation at all times these visualizers will also react to my voice or any sound microphone picks up you can see that we are getting values in a wave that goes between negative and positive values centered around baseline of zero we can also represent audio by drawing lines i start a new shape by calling built in canvas begin path method move to method is used to set starting x and y coordinates of a path so i pass it this dot x and this dot y from line 9 and 10. we are generating these x and y coordinates here by passing them to class constructor line 2 method sets points along a path in our case we are drawing a single line so it will represent ending x and y coordinates of our path i pass it the same horizontal coordinate so this dot x but vertical ending point will be this dot height from line 12. this value is updated depending on incoming audio on line 16. i call ctx stroke to actually draw the path we just mapped i delete fill rectangle on line 20. stroke style is black by default and we have black background i set stroke style to this dot color from line 13. now we are drawing lines instead of rectangles i can play with these values what if i pass it this dot y or what if i put dynamic this dot height here and this dot y here i think it's clear now how to make visualizer in a row like this you can play with it and come up with much nicer ones i want to build a circular visualizer now one way to do that is by translating and rotating canvas context whenever we are rotating and translating canvas graphics usually we don't want these translates and rotates to spill out to other drawings so we wrap it between built-in save and restore methods like this we call save to create a snapshot of current canvas properties and settings then we can do anything we want here translate rotate scale change colors and so on and then we call restore which will look at the last save call and reset canvas properties and values back to what they were at that point in time now i want rotation center point to be exactly in the middle of canvas so i can create a nice circular audio visualizer i will use built-in canvas translate method this method takes two values for x and y and it will translate coordinates 0 0 that are normally in the top left corner of canvas it will translate them to these coordinates we pass to it we do it because rotate method we will call next takes coordinates 0 0 as rotation center point i pass it canvas width divided by 2 and canvas height divided by 2. it will move everything as if this position was coordinated 0 0 on canvas now i want to rotate around that center point so i call built-in canvas rotate method it expects the value in radians to know how much i want to rotate the drawing i pass it 1 radian which is around 57 degrees full circle is 360 degrees which is around 6.2 radians we don't really want to rotate all the bars the same i want each bar to have different rotation based on their index on their position inside bars array to do that i need to somehow keep track of index from this for loop that creates my bars inside the bar class itself i do it by passing the index to bar class constructor as the sixth argument on line 8 i need to make sure my class constructor expects that argument and i assign it variable name for example index i created this.index property and i assign it to the index that was passed on line 8. now i can pass this.index property from line 14 to rotate method on line 24. i need to make sure i spell index correctly here as the for loop inside create bars runs 256 times and index is increasing that value is being passed to rotate method and each of our animated bars will have different rotation interesting shape if i want the lines to start from the middle of the screen i need to change starting x and y coordinates to 0 0 because if you remember we translated coordinate 0 0 to the middle of canvas using built in canvas translate method on line 22. now my audio bars stretch from the center if i set ending line coordinates to 0 and distort height we get the simplest version of circular audio visualizer it looks nice but we can do so much more with this keep in mind that to see any movement your microphone needs to be picking up some audio i'm playing music into my microphone now so that i get constant motion you can try to play with the values we passed to move to and line two methods to see how it reacts the value that is updated by microphone input is the distal height so that will always be the dynamic part we set it up that way on line 17. i could also be changing this.x and this.y for example i can also be changing colors based on mic input we can do so many things here we can adjust how much we rotate our visualizer by adjusting angle value we pass to rotate method on line 23. i set starting coordinates on line 26 back to zero zero i try to change rotation on line 23 to something else the visualizer is moving very fast i want to add some ease in some animation to the bars for example i want them to grow very fast when loud audio sample comes to make it look reactive but i want them to shrink back to zero much slower i think that will look better let's try i will create a helper variable here it will calculate the values before we assign them to distant height constant variable i call for example sound is equal to mic input times 1000 if sound is more than current distorted height set this slot height to sound i want the visualizer to still be fast reacting let's adjust rotation on line 28 okay i want the shrinking of the bars to be animated so here i'm saying if sound which represents current mic input is more than the current height make height match that value immediately so bars will grow instantly else meaning when microphone input is lower than the current height starts to decrease height slowly so let's try this dot height minus equals distant height times 0.9 this is still very fast and almost instant how about 0.1 now we are starting to see some animation and ease in when the bars shrink let's decrease height by its own value times 0.01 which is basically saying decrease height by one percent of its current value for every frame that's very slow how about five percent i can change rotation of the visualizer by adjusting values in radians we pass to rotate method on line 28. again i adjust easen animation on line 21 0.03 is nice decreasing height by three percent of its current value for each frame we don't have to start from the middle all lines don't have to start from one point how about i make them start from this dot x and this.y coordinates we are starting to get some cool unique visualizers if you are coding with me you can try how each visualizer we make reacts to your voice and then you can try to play some music into your microphone it's always more fun when you make it animate to your favorite songs what if i try to put this.y here keep in mind that this dot x and this dot y values are being pushed away from the center because we are translating and rotating canvas on lines 27 and 28. if you want to fully understand translates and rotates so you can put these values in with intention to get specific results i also have a course on that i can also change the visualizer by passing different initial values to our 256 objects at the point where we create them here i can give them x position of 0 for example i really like what happens if you tie vertical y position of the bars to index instead like this maybe i times 2 change in width doesn't do anything since we are drawing lines we are not using width right now in our drawing code we used it for rectangles before initial height also doesn't matter now since we are constantly overriding it with audio coming from microphone changing this value here will make the spiral different size maybe 1.5 we made a nice rainbow spiral visualizer using lines with move 2 and line 2 methods we can also give it more moving parts for example i can attach rectangles to each line i use stroke rectangle method i just pass it x y width and height now our visualizer is made from lines and very thin long rectangles it's starting to look much more dynamic i can change width of these rectangles here on line 45 i set it back to 5 and on line 34 i set width of the rectangle to my dynamic distort height variable that is constantly changing based on incoming audio values maybe height divided by 2 i can try anything i can pass it this dot y as x coordinate since we are rotating canvas it's giving me these interesting mathematical shapes now i kind of have one spiral of lines and another separate spiral of rectangles if i set vertical coordinates to dynamic height value it will just be pushing the entire rectangle shape away from the center height of the rectangles can also be hard-coded for example 5 pixels to get this effect we also wrote getvolume method on microphone class that gives us a single average volume value of all audio samples coming from the microphone let's use it for something inside animation loop i create a variable called for example volume and i set it equal to microphone from line 39 dot get volume so as the animation loop runs we will be getting updated value for total average volume i will pass this new volume variable to draw method here so that i can use it in my drawing code up here on line 24 i will make sure that draw method expects this volume argument we are already translating and rotating canvas here we can also use built-in canvas scale method scale method expects two arguments for horizontal and vertical scale so i pass it 2 2 which will double size of the entire effect i can also make x very small like this we can play with these values and see what we get let's just leave the effect at the original size so 1 1 and i will add current volume to it like this now my entire visualizer pulses like a speaker as the average volume changes we can change how much volume affects scaling by multiplying it by different values we can also give a different horizontal and vertical scale if we want to what if i want the entire visualizer to rotate a little and i want the speed of the rotation to depend on volume i will do it down here inside animation loop first i declare a led variable i call angle initially it will be zero then i wrap my entire drawing code inside save and restore methods i will call canvas rotate method and i pass it angle from line 51. i increase that angle by 0.1 for every frame maybe a smaller number you can see that rotation center point is at coordinates 0 0 in the top left corner so the entire visualizer spins around that point i actually want it to spin around its own center point which we set to the middle of canvas so i use translate method before my rotate call and here i translate rotation center point to be in the middle of canvas both vertically and horizontally scale translate and rotate are additive so if you call them twice it will just add up i'm also calling translate here on line 27 inside the draw method on bar class i need to change these values to 0 0 because at this point it's already been translated by that other translate call inside animate loop nice i can change the speed of spin here on line 60. i can also reverse the direction by doing minus equals like this let's tie volume into the rotation speed by saying plus volume now if microphone audio gets loud the entire visualizer spins much faster i will make that volume value smaller you can play with this to get motion you like if you scream to your microphone you will notice your visualizer starts spinning very fast if you get silent it will slow down to the base rotation speed we use volume to make the entire visualizer pulse like a speaker with canvas scale method and we also tied rotation speed to the current volume our visualizer currently works with 256 audio samples which i hardcoded into the project let's make it dynamic if i change fft size to 1024 this will give us 512 audio samples it's always half of fft size value it's hardcoded here and here so i have to manually change it if i want to work with different amount of samples better way to do this would be if i pass fft size as an argument to microphone class constructor then i can say fft this.analyzer.fftsize is equal to fft size that was passed as an argument on line two this gives me an error because i need to pass that argument to my constructor when i instantiate microphone class let's declare it as a variable i call fft size now i pass this variable to microphone class and i also use the same variable to calculate bar width and also inside the for loop that creates audiobar objects it has to be half of that value as we said before frequency bin count which is the number of audio samples is always half of fft size you can just change this single value of fft size and it will correctly set up my microphone and visualizer to adjust to the number of requested audio samples fft size takes only specific values if you put a different value you will get an error also since each audio sample triggers one line and one rectangle to be drawn on canvas if you notice some fps drops in your animation the easiest way to fix it is to come here on line 40 and set fft size to a smaller value to reduce the number of draw calls canvas has to do for every animation frame i can think of many more different ways to make this effect interesting let's try some more experiments together we are using move 2 and line 2 method to draw a line and stroke rectangle to draw rectangle i can adjust values i pass to the rectangles to change the shape of spiral we are getting here i can also adjust the rotation by using another rotate call interesting we can also rotate them the other way by using negative values i will leave that for you to experiment with i comment out the rectangles let's try to use circles begin path canvas arc method i pass it x y radius will be dynamic so this dot height times 0.2 start angle 0 and end angle mastered pi times 2 and we stroke it i can adjust x value like this for example to make it spiral differently i can also make them larger by changing value i pass for radius of these circles if you are noticing performance issues you can fix it here on line 45 by using less audio samples we can also draw flexible rubbery lines instead of our straight lines with built-in canvas method called bezier curve 2. it takes 6 arguments starting x and y coordinates middle point coordinates and ending coordinates it will draw a curved line between these three points so let's try to give it hundred hundred for starting x and y this dot height for both middle point coordinates and this dot x and this dot y for ending coordinates do you see how they curve now it's a nice rubber band effect i comment out the circle so we can see it better i can experiment by passing it different values and watch what happens this is really fun let me know in the comments if you are still coding at this point have you used bezier curve 2 method before or is this your first time if i uncomment the circles we have a lot going on on canvas calculating a draw in so many curved paths and circles is performance expensive sometimes we also have to use our creativity to make our effects look good while not using up too many resources at this point i'm just experimenting and playing with the code let's bring animated pumpkin into the project radu builds it step by step in the second part of this tutorial he will teach you everything i can just bring it into the project by instantiating pumpkin class like this i pass it x and y coordinates and size then in animation loop we calculate soft volume to make the values less jumpy to make the transitions between volume values more gradual we have a global variable called soft volume on line 65 it is storing soft volume value from the previous frame for each animation frame we soften the volume transitions by using 90 of soft volume value from previous frame and 10 of the current incoming microphone value it will very quickly even out and it will give us responsive but the gradual and less jumpy sequence of numbers representing current microphone volume if you pass this soft volume to draw method and pass it to scale and rotate methods instead of raw volume value we are passing to these methods right now you will clearly see the difference now i can just call pumpkin a draw and i pass it ctx and soft volume i can make the pumpkin larger i calculate variable i call for example openness and it will be soft volume times 7 and i pass it to the pumpkin like this if you want to know how this works check out radu's video i'll link that and our other audio effect tutorials in the video description have fun
Info
Channel: Franks laboratory
Views: 9,270
Rating: undefined out of 5
Keywords: Audio Animations, web audio API, javascript audio, audio visualiser, audio visualizer, JavaScript Tutorial For Beginners, JavaScript Tutorial, javascript for beginners, learn javascript for beginners, JavaScript audio, learn JavaScript, learn javascript in 1 hour, javascript visualization, javascript visualizers, audio visualization, audio visualizers, javascript, html canvas, html5 canvas, html5, css3, creative coding, franks laboratory, frankslaboratory
Id: qNEb9of714U
Channel Id: undefined
Length: 55min 5sec (3305 seconds)
Published: Fri Nov 12 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.