Juce Tutorial 56 - Graphics and the Timer Class

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody before we get started just a really quick announcement our good friend Matt cat music has opened up enrollment for his programming for musicians course so due to the success of the last course that he did on teaching C++ from your musicians he's decided to open up enrollment again for another six weeks starting on Saturday so there are only three days left to order and you can save 15% with the discount code the audio programmer just used that code on checkout to enroll be sure to go to the audio programmer comm to sign up and another quick reminder if you're not signed up to our audio programming community on this cord be sure to come check us out so we have audio programmers from around the world all different levels everybody from professional developers at places like Rolly Native Instruments Ableton so on all the way down to teenagers that are just type typing their first lines of code and everything in between and we're all discussing different questions around audio programming so it's a community for everybody and if you're not there yet I'd love to see you there so be sure to check us out and be sure to sign up if you're interested for programming for musicians on the audio program or comm hey what's up everybody I'd like to welcome you to another juice tutorial and in this tutorial what we're going to do is take things back to the basics and start doing a few of the beginner juice tutorials for people that are just getting started with juice and one of the most common questions that we get in the discord chat is about painting graphics to the screen we get a lot of people that say hey I've drawn something in my paint function but and the the thing is supposed to move but it's not moving what's happening and the reason that that's not happening is because we is because people haven't called repaint and in order to call repaint you have to use a timer that calls repaint time and time again and that's what we're going to talk about for this tutorial we're going to build a very simple project that's going to have a ball that's going to just kind of go across the screen and so the ball is going to be a motion and then I'm going to show you some basic concepts around how to actually repaint the ball so that it continuously kind of paints and draws in another component so we're going to create another project here so this is just gonna be a regular audio application same kind of concepts apply for a if you're building a plugin so I'll call this timer component and after I'm done I'll upload this on my github so you can check it out and experiment on your own if you'd like so we're going to hit create and then what we'll do is we will just open this in our IDE and here we are and Xcode and so let's just go ahead and open quickly the juice API so you could do that through juice com slash dot slash classes this will take you to our API and so the the class that we're going to use here is called the timer class so if we scroll down here we will see the timer class and it says makes repeated callbacks to a virtual method at a specified time interval okay so what it means by virtual method mean what that what that means is that we don't actually have to create an object of of timer okay we don't actually have to create a timer object in order to be able to use this the timer's already kind of there virtually and we can call it we can call the timer to start or to stop and I'm going to show you exactly how to do so if you're coming if you're like me coming from a background of kind of processing or p5.js where you have kind of avoid setup and avoid draw type of workflow where you have one function that kind of happens once when you initially setup your app or your your creation and then you have another you have another function that's called void draw where it continuously kind of repaints in the background okay and then if you're moving to juice you might say to yourself a where's void draw right and this is kind of the same sort of concept something that kind of continuously calls in the background okay so I'm going to show you how to do this so like I said it's a pure virtual method so what that means is that we don't actually have to create a timer object we can just actually call it but we will see here that we have this virtual void timer callback and then we have this equals zero and what that means is that if we inherit from this class then what we need to do is we need to actually implement this function in order for the in in order for our project to compile or else it will not or else it will not compile okay and I will show you that really quick so here we are in our main component header file so the first thing that we want to do is we want to inherit the timer class so what we're doing is we're actually we actually want to say hey in this main component class now I want to bring in this timer functionality so that I can I can call on this and that's exactly what we're doing here so what we'll do is we'll just make this public and then we're just calling it the class as we can see here we've got this class here that's just called timer and that's exactly what we've what we put there okay so now and when it goes green that's a good sign that we've done something right so and so like I said this is this is a virtual method so we don't want to do something like this where we create an object of timer of timer right we don't want to do that because it's a pure is is a it's a virtual class so what we could do is we can go back to our API here and then if we scroll down here like I said we have to implement this virtual method called timer callback and so what we're doing what we'll do is we'll just put this here so we what that means is that we have to create this method called timer callback within this within this class and since we are since this is a pure virtual function we want to use the override keyword and the override keyword just lets readers of the code know that that this timer callback is a pure virtual function that we're calling from one of the classes that were inheriting from okay so so now we need to implement that so we've declared it now we need to implement it and if we just scroll down here and I will do void because it's and then this is our class main component and then the method is called timer callback and now I've just implemented it there and now we will just compile this just to make sure that this actually compiles and now we have just a blank screen there's nothing in there so so now what we want to do is we want to do something with this timer callback so now if we go back to our documentation here and we look on our methods so we have a timer callback it's going to get it's going to get called back periodically so it's going to be called periodically and we need to actually tell it how often we want it to to call so a typical time for something like this would just be something like 60 Hertz ok just means that it that it calls 60 times a second so so you might ask yourself okay with this virtual method if I don't if I don't have if I don't have a timer object how do I actually call it so the way that we do it is we can just go here into our main component constructor so the main component so the constructor is what calls when our app is first set up so this only calls once kind of like void set up so to speak and so the way we do this if we don't if it's a virtual method is we actually just call the class and then we use the scope operator I believe it's called and then we want start timer and Hertz and here I will just put how often I wanted to call every second so 60 times a second okay so now the timer so now the timer has started and then we have the destructor we know it's a destructor because we have this little tilde object here that says this is what happens when the when the main component actually destroys and what we want to do is we want to stop the timer stop timer okay so that's one of the things that we want to do when the app is shutting down I want to say hey stop the timer so so now so now we have this and now we want to create something let's just make a another component where we have a ball that goes across the screen when it gets to the end of the screen it bounces back so what we need to do is we need to create another component class okay so we will exit out of Xcode and just minimize this for now and then in our producer we will just hit this little plus button down here under the File Explorer and then we have this add new component class split between a CPP and header and I will call this I'll just call it ball and I always do this where I save it outside of the source folder but just drag them in there so now we have our ball cpp in ball dot h and now we open xcode again and so now we want to go ahead and start creating our ball so as we can see this is a component class so the component class just means that it's something it's a rectangle essentially that's drawn on this throne on the screen so you can have a slider within your component you could have a dial you can have a ball bouncing somewhere whatever you want to draw within this component you could draw it and then what we would do since ball is a child component of the main component then we can draw we can draw this ball component as big or as small as we want to write and I will show you how that how that works so we have this void paint function here so this is what happens this is what actually draws our graphics to the screen so I'm just going to just take all of this I'm just going to delete it and then first thing that we're going to do is we're just going to paint the background we'll paint the background black right so what we could do is we have if so if we want to look at what what can we actually call in this paint method then what we could do is we can go back to our our Juice API here and we can actually go to the graphics class which is right here at the top okay and and so I'm going through this quite slow just to show people a little bit how to read the actual documentation of the juice API and just how to kind of make sense of what they're seeing in in the in the juice framework so we see that we have a juice so that we have a graphics object we know it's a graphics object because it has a capital G so this is a reference to a graphics object and so we can call we can basically call ji-suk color G set opacity so on and so forth so I'm gonna use one that's called fill all so so if I go here then I see that I have this fill all functioned here that I can call and then in here I can put a color so let's say that I don't know what color I'm what what how how to actually declare this so what I could do is I can actually just open that up in a separate tab there like that and then we have the color class and then it says I can actually call it call a color and you have loads of colors I'm not going to go through all this but you can you can use RGB you can use HSB if you want to or you can use one of the kind of built-in colors and that's what we're going to do here so once again we go G dot fill all and then now I have a color and I could go colors it's actually the colors and then what I could do is I could just call one of these one of these colors here so there's loads and I'm just gonna call it black so if I command click in here in colors you will see that it has all a list of all the colors that we could actually call so you can make it light salmon you can make it goldenrod yellow if you want to loads of different colors in there okay so but for now we're just going to make it black so now what we want to do is we want to make a ball or a spear or any lips so luckily the juice class graphics class has a function for that so if we go to ellipse so we see that we can we can call this a couple different ways we can call it using an x and y position and then how how wide and how tall we want the ellipse to be we could use a rectangle object okay we can do the the XY with high thing along with line thickness if we want to and then we can do we can do another rectangle with the line thickness so let's just try this so the float X X and Y is just a starting x and y position and then the width and the height pretty self-explanatory but let's just let's just try it let's just try using this draw ellipse using the rectangle object here inside here because I want to show you this because this is a little bit this is very useful to use here in induce the rectangle the rectangle object okay so what I can do is I can declare a rectangle object and this just literally draws a rectangle okay and rectangle and this is going to be of type float and we will just call this area and then what I could do is if I look into the rectangle class that you see how I'm just going into a class and then and then we see that we have parameters that we got to fill in so then we've got to go into another class and see what we need to do to actually create that object right so we need to create a rectangle object so here we have initial X initial Y and then width and height so what we could do is we could just use we could just initialize this rectangle object that we've just created called area by just using initial X so I'll put a 10 and 10 and I will make and I will make the ellipse let's say let's just say 20 20 by 20 20 pixels by 20 pixels right so now I've just created this rectangle object and now I want to go back to my ellipse and I can and essentially what it does is it creates a rectangle and then like the REC you can't actually see the rectangle it self but the circle is in within the rectangle so the rectangle is just defining the area of the circle so to speak so I could do G dot draw ellipse and now we see that we have this this rectangle object that we can put in here so I can just call this area and then line thickness let's just say 2.0 for now and so now we've said so now we've drawn an ellipse but there's another problem actually now that I think of it the problem is is that the ellipse that we've drawn so we've selected we don't we haven't told it what color that we want the ellipse to be so let's just go ahead and draw and set the color so we could use that we could do that using set color and then we could do colors let's do like goldenrod yellow right so now we've set this so now we set the color to golden light goldenrod yellow and now we've drawn the circle so now we've got this we've got this ball class where we've drawn where we've drawn a ball but now what we need to do is we need to actually get this to draw in our main component because if we compile here we will see that there's nothing there even though we've drawn a yellow ball so why not the reason is because we have to now declare the ball class we now have to create a ball object within our main component so our main component is kind of like our processing center where we where we have where everything kind of feeds into so it's kind of the root of our tree so to speak so first thing that needs to do is it needs to know about our ball header file so the first thing that we need to do is we need to actually use includes so we got hashtag include and then ball dot H so now we've actually got the functionality for ball dot four for our ball object that we've just created and now we can just call this by saying ball ball right so we've just so now we're just creating an instance of the ball now if we go into our main component what we can do so I'm just gonna get rid of all this because we don't actually need it and I'm gonna get rid of all this code all this all these comments and stuff so now what we can do is we need to add it as a child component to our main component so we're basically saying hey main component you now have a child component that that called ball okay and we want to add and make it visible and then I could just put ball in there okay but then we compile it right and we will see that we still see nothing right we don't see anything the reason that we don't see anything is because we haven't told the ball object how large we want it to be okay and we can do that down here in resized okay so resized gets called when the when the when the main component first gets created and then anytime that the component is actually resized okay so what we could do is we could do ball set bounds and then here let's just say that we want it to be get the width of the component that we're in minus 100 and then we could do get the height minus 100 and then we'll make this 200 by 200 so that'll be the size of our whole component not the size of the ball itself the size of the whole component so and then what I could do is I can just go into the paint method of the main component I can erase this I could do G dot fill all and we'll make this colors white so now what we should see is we should see a white screen with a black with a black square in the middle with a yellow circle okay so we see the so we see the white screen oh I meant to call this get with / - my bad but we see that it's ever here in the right hand corner so what I could do is I could just go back here and I could do get with / to get height / - and that should put it in the middle of the screen okay and so now we see now we see the circle and now this is and now this is in the middle of our component and as we can as we see here we can we can make this any size that we want right so I could if I just cut this out for a second I could actually say get local bounds which gets the gets the width and the height of the parent component which is our main component right so what we should see now is an all black screen with a yellow with with the yellow with a yellow ball like like so so now we see that so the main component the the white background is here is just beneath this black canvas here so we've actually painted this over top of our white canvas okay so now we have this I'm gonna change this back and we can like just to just to make it just to kind of send the point home here I will put this at I could put this at the origin and I can make this 300 by 300 if I wanted to and it'll put it in the left-hand corner okay which is our origin and make it 300 300 so we can really make this any size and configuration that we want okay but I will just put it in the middle of the screen so now so now what we're now what we need to do is we need to think about moving this ball right so if we go back to our ball dot H then or ball dot CPP rather we'll see that we have this rectangle object where we've set some initial coordinates so what we need to do is we need to actually we need to actually move this now so so where where this x and y coordinate is changing so what happens is that it's kind of like drawing a cartoon where every time that it that we call the repaint method so every time we call repaint on this ball component then it should draw our ball in a new place okay so let's let's just give that a try here so let's think about this for a second so one thing that is interesting that I was I was talking with Chris Randall from audio damage a little bit earlier and he's one of the leading UI designers in music tech and he actually looked at this Twitter post that I made earlier and he pointed out that I had actually drawn all this stuff in my paint method and that I should actually be making the changes to where the ball is in the timer in the timer call back in the main component the reason is that if I was using a plug-in then what would happen is that when you when you actually closed so so you know when you have a plug-in you pull up the graphical display and you can actually see the graphics and what happens is that when you when you actually close that down in a plug-in that actually destroys that come I believe so so what happens is that anything that's happening in the paint method of a ball or in your editor if you're working in a plug-in would actually not be happening anymore because it's not there anymore so what you want to do is you actually want that to be happening in your processor if you're if you're using a plug-in or in your main component if you're using an audio app like I'm using so that ensures that any changes that are happening are still happening even when the UI is actually closed okay so that's the reason why we're going to do this a little bit more complicated so I'll do it I'll do it this this initial way and then we will actually change it change it over because I want to start it off simple so what we'll do is we'll make a we'll make a int we will call it pause X and we will call that we will initialize it with a value of 10 and then we'll do a pause Y and we will make that 10 because that and then what we could do is we could do pause X and pause Y so I've just made variables there that have replaced the numbers okay so we will see here that it complains here because as saying cannot be narrowed from type int to float in the initializer list the reason that that's the case is because we made a rectangle of type float not a rectangle of type int so that's the reason that I need to go back here and change this to float to change this to float like so and then we will see that it's just stop complaining hopefully okay so as we can see we still have our ball it's still not moving Xcode is being funny yeah sometimes it shows the errors when they're not actually there anymore so now what we need to do is we need to move we need to move this across right so what I could do is I could say well let's let's just make float let's just say speed X and then we will set that with the value of one to start off with and then what I can do is I can just say I will do it down here just so we have a logical kind of storyline so to speak so we could say pause X so I'll show you the long way and then I'll show you this short way so we got pause x equals pause at so that's one way we could write it we could also write it like this okay if we want to shorten it down a little bit we could do positive pause X plus equal speed X and that means the same thing okay so once again I will hit play and we will see that it's still not moving right still not doing anything even though we've called for the positive position of X to add to to add every time it calls this paint method it should add the speed of X to pause X which is one and it's still not doing it well why is that happening the reason it's happening is because we haven't called repaint so this is the whole purpose going back to our timer call back the timer call back is getting called 60 times a second and what we could do now is we can actually say ball dot repaint and what that does is that actually calls the paint method over and over again on the on our ball object and we will see that now the ball is moving across the screen right so we'll do that really quickly again drag it over we see that the ball is moving over so great so that's so that's fine right now let's now let's make this a little bit more complicated unless say okay well the ball disappears because it's always going positive in the x-direction so we what if we want it to bounce back alright so we will do this piece by piece and then we'll optimize a little bit afterwards okay so we got if pause X or is if pause X is greater than or equal to get with then we should do speed x equals minus B X okay so then what that does is it just changes just changes it back to two it just flips it around so that we are actually going back in the other direction hopefully unless my math is wrong so we got this and we see that it bounces back okay and then it disappears okay well we saw that so we observed a couple things here we observed that the ball actually kind of went all the way off the screen it didn't bounce like a real ball should bounce on the screen and that's the reason the reason for that is that when we create this rectangle area here we have posix and paz y which are ten ten and that's starting from the top left-hand corner of the ball okay so that's starting from the top left-hand corner of the ball so what we need to do is we can we can create a variable so so rather than putting 20 so our ball size is 20 right so rather than saying get width minus 20 and then we have 20 and we have 20 again what we could do is we can actually create another variable so we've got float let's just call this size and we will say that it's 20 okay and this is something that that when we find ourselves kind of repeating repeating the same number or repeating the same thing over and over again and referring to the same thing is better for us to to have this in one place so that if we wanted to change the size of the ball and we wanted if we just had 20 everywhere then we'd have to change 20 a million times everywhere where we put 20 we had that we would have to go back and change it but since we've only got one variable called size then what we did what we're doing there is we're just saying hey we just want to we just changed this one number we can change it to ten or we can change it to 15 or a million and it will change everywhere that we have this so so we got pause X is greater than or equal to get with - size right and what we should see here is that this should go to the edge and boom you see that it bounces like a regular object right and then it disappears off the screen so now we need logic for that so we can use or pause X is less than or equal to zero because we because we're already on the left hands like I said the position of the ball is from the top left hand side so it will be when it's when the ball gets left hand side of the ball gets to position zero of the width then that's really actually zero so we don't have to do any sort of offset or anything like we did for for the when it got to the right hand side so now we will see that it goes to the left or to the right rather and then to the left and now we will be infinitely going between zero and get with great okay so let's do this for the same thing in the Y Direction right so we could say float speed Y and then I'll say let's just make it a different different number three and then we will just do this we will do the same thing plus equals speed Y and then we just need to do the same thing same sort of logic so if pause Y square then or equal to get height because we're going in the Y Direction minus the size or pause why it's less than or equal to zero and then we've got speed y equals negative speed y so now we should get a ball that's going and now we see that it's going all over the place now right so now we so now we have this repainting the way that we want to and everything but following Chris's advice we need to take all of this logic and we need to now bring it over into our timer component okay because there are a couple reasons well one reason is that because the paint so this is something I know know a bit about not I'm not an expert on but the the repaint the repaint calling only gets called it doesn't get called every time this time we call got back it's called because repaint so so that's because our graphics is kind of secondary to what our audio is doing okay so it's not on a high priority thread so so our audio call back if we had audio that would be happening on what's called a high priority thread what that means is that no matter what the audio callback has to get called okay but the graphics the graphics callback does not get called every time so to speak so what that means is that is that sometimes is that sometimes this timer call back may actually get called but repaint does not actually happen until it's kind of convenient for for it to happen within the thread system okay so what that means is that and that along with the the problem I described for you earlier where we have where we have the if if we were running in an in a plugin rather than an audio app where we have a window that's opening and closing or even if if in here we had like this window and the window opened the window closed what would happen is that if we killed off the window so when we close the window then that logic this logic that we have in here and the paint method that doesn't exist anymore so to speak and so if we have some sort of LFO or something that's some sort of sound that this the circle is supposed to be representing the supposed to be moving so if that's not if if that component doesn't exist anymore it's not getting called anymore then this logic isn't happening so what would happen is that the audio would just not move the way that it's supposed to so now we need to take all of this and we need to actually move it to our timer so we're just gonna cut this and just gonna add a couple lines of space here I'm just gonna paste this in for now so and I will just point out a couple little principle here so as you can see in the class that I created of ball I actually have these variables the pause X pause Y so on and so forth these are actually the end our public declared as public so public means that we can actually we can actually access these variables from another class okay so so what we need to do is we need to actually go in here and we will see that it doesn't recognize in our main component because we've moved this to a different class we've moved this to a different class now and saying pause X I don't know what you mean by pause X okay but you remember that we created this object called ball and what we need to do now is we need to say hey we're and about ball the ball pause X and the ball speed X so you got ball dot pause X balled out speed X and we will just do this for all of these right okay and now we get to a tricky one that's easy to overlook get with actually needs to be ball dot get with because we are talking about the the actual dimensions of the ball component not the dimensions of the component that we're in now okay so we got balled that size that speed X and so all of these okay and now this should compile for us should work and we see that it works just the same but now we've kind of optimized this so that this will be calling all the time no matter if this window was open or closed or whatever so that's it so that's so that's the tutorial on repainting components using the timer class and that's the end of the tutorial so I hope you've enjoyed this and found this useful and I will see you next time
Info
Channel: The Audio Programmer
Views: 1,782
Rating: undefined out of 5
Keywords: juce, juce framework, c++, audio, tutorial, audio programming, creative programming, creative coding, dsp, digital signal processing, vst, create vst, create plugin, audio plugin, oscillator, synthesizer, maximilian, openframeworks, software development, beginner, easy, max msp
Id: U5eHees1qTE
Channel Id: undefined
Length: 41min 22sec (2482 seconds)
Published: Tue Jul 30 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.