A drum machine is a fun project to create to practice your Python skills.
We just published a full course on the freeCodeCamp.org YouTube channel that will teach you how to create a drum machine project using Python and Pygame.
Pete LeMaster created this course. Pete has created a bunch of tutorials on his own channel and has now shared this course with the freeCodeCamp channel.
First the video shows off the project and then it goes into a detailed tutorial showing how to add a bunch of functionality line-by-line.
This course is for both beginners and experienced developers. It covers Python and Object Oriented Programming concepts including nested for loops, functions, using audio files for generating sound, and saving / reading data.
Here are the sections in this course:
- Project Showcase
- Setting Up the App
- Drawing the Board
- Turning Notes On and Off
- Add A Moving Beat Tracker
- Adding Sounds and Making them Play!
- Add Play/Pause Functionality
- Adjust Total Beats and Speed
- Turn an Instrument On or Off
- Epic Water Break Content
- Drawing the Save and Load Buttons
- Adding Clear/Reset Board Functionality
- Drawing the Save and Load Menus
- Saving Beat Information
- Loading In Saved Beats
- Clean Up and Final Troubleshooting
Watch the full course below or on the freeCodeCamp.org YouTube channel (3-hour watch).
You're about to learn how to create this cool beat maker application from scratch using Python and Pygame.
This is a great project for both beginners and experienced developers.
Pete LeMaster created this course first, Pete will show off the project.
And then he will teach you how to code the project line by line, check the description for a link to the assets you need, plus the final code.
Good luck with this project.
And feel free to leave a comment with anything you learn in this tutorial.
Alright, so I'm super excited to show you guys this project showcase.
This is one of the coolest projects I've ever built.
And I think you could really enjoy building something similar as well.
So the key features of this app include the ability to be able to quickly create and edit brand new beats as well as the ability to modify the speed at which your loop plays and the total number of beats in that pattern.
The buttons on the bottom gives you the ability to quickly Pause or Resume playing the beat or clear the entire board out when you're ready to restart you can turn entire channels of instruments off so that you can edit certain parts of your beat while keeping the whole thing playing.
Then when you get something you really like the Save menu lets you save that under a name of your choosing that you can load it back in later and revisit some of your favorite creations this tool lets you create some really unique sounds and I hope you enjoy the project.
So follow along with the tutorial, grab the code if you want to from the link in the description below.
Leave a comment letting me know what additional features you'd like to see in this kind of project.
Or what you'd like to see on the channel in the future.
If you enjoy the video, be sure to leave a like on the video and subscribe to the channel for tons more great content.
Now let's get into the tutorial.
All right, super excited to bring you guys this tutorial.
But it is a long one.
So let's get right into it.
And I'll explain what we're doing as we do it.
So step one is going to be importing Pygame.
If you're familiar with the PIP module, then you can use PIP and do pip install PI game.
Or if you have an IDE, good one like pi charm, which I use, then you usually can do an import statement like that.
And as long as it rec recognizes your module name, it'll take care of the import for you.
And then I would say because this is a heavily music themed application, import the mixer right up front.
So Pygame dot mixer is kind of pi games associated sound effects and music handling tool.
So we're just gonna do that right in the beginning.
And then we're going to do pygame.in it to kind of initialize it, which will need for fonts and using a lot of the built in functionality.
Okay, so that's just how we're going to start it.
And next, let's set up our screen.
And since this beat making software, if you think about it, it's kind of you want the same dimensions as your actual screen so wider than it is tall, because we're anticipating the beats kind of stretching across the screen.
So I use 1400 by 800.
And I kind of like that, but you can play around with this stylistically if you want to.
And I just defined a few RGB colors right up front, because I know pretty much every app I make, I'm going to use black, white and some shade of gray, maybe 50 of them along the way.
And so I just do like black, white, gray.
And then when I add other colors later in the project, like I'll for sure be using some like red and maybe a gold in this project.
I'll add them up here.
But we don't need that right now.
So let's keep going.
And then the next thing, we're just going to focus on getting the screen created real quick.
So it's Pygame dot display, dot set mode, set mode.
And then in square brackets just do with comma height.
There we go.
And you could type those numbers directly here, you don't have to put them in a variable.
This is much better practice.
And if you want to change it later, it's a little easier to track down.
Something else I like to do technically, this would be considered an optional step.
But I always like to set the caption.
And I'm just calling this one beat maker.
You can call it something else if you want.
And then I'm going to set up a font right here, which I'll call label font because it's gonna be a little bigger.
But I always create a text right in the beginning because as soon as you need text in your game, you're really going to want to have this initialized already.
Otherwise, you're just gonna have to come back and do this step later.
So I say this in almost every project But if you don't want to go and get a ttf file, almost everyone's computer and install of pi game is going to come with this one that you see right here free sans bold that TTF.
That's like a built in.
So you can use that one, if you just want to follow along and you don't care too much about style, I went and grabbed a free one off the internet, that's just called Roboto bold dot TTF.
You can see right here in my file structure.
So if you want grab a font for your project and make it your own, just drop that file right in there and then call it just like this.
And then the only other thing you have to give it here is font size.
So we'll give it 32.
And that's, we're also going to do FPS.
So that's our framerate, and we're going to set up a timer, which is going to control the speed of our game, which for a music based application is super important.
So we'll do timer equals pi Game dot time dot clock, some people will call this clock, some people call it time, some people will just do this directly in the game loop.
I don't like doing that.
But make sure you have something along this line.
And let's go ahead and create our what I call the main game loop.
So we go just underneath this.
And obviously, there's going to be a lot of stuff going on in between are kind of our variable library and our main game loop.
But just to get it just to get it started, we're going to do this.
So we'll set this variable run equal to true.
And then we're going to set up a while loop that's wall run.
And the first few things you always do while run is timer dot TIG at your frame rate.
So now this is saying as long as run is true, we're going to execute this code 60 times per second.
So that's the purpose of FPS.
And since a lot of our functionality is going to be move on to the next beat every second, every you know, half second, whatever.
This timer dot tick is super important for this app.
So frame rate, you want to keep it at 60.
If not, if you use a different frame rate for some reason, just make sure that when we get to the part of the math later, where we calculate how many beats per minute that you use your frame rate in that math, okay, so then we're going to do screen dot fill.
And we're going to make the background black, I think that looks pretty good.
And let's go ahead and set up what's I always call this event handling, but it's basically just getting all of the occurrences that are actually happening on your computer.
So it's for event in PI Game dot event dot get.
And this little application here, every code we put, all the code we put inside this for loop is going to be checking all the keys on the keyboard, the movement of the mouse, any any other event that the computer can process is going to be inside for event in PI Game dot event dot get.
And the first one you want to set up just so your game will run is if event dot type is equal to and then it's pi Game dot quit just like this all caps.
And if that's the case, then we just want run to be equal to false.
And that's all we're gonna do for now.
But we are for sure going to be putting a lot of functionality in there later.
Okay, and then outside of this, we want to do Pygame dot display display dot flip.
And that kind of throws everything onto the screen.
And then we'll do this last one is just going to be Pygame dot quit just like that.
So outside of any other code, just on the off chance it gets to that point.
Okay, so reformat the format.
So now we should just get the shell of our project, and it closed right away, because I said robot bold, and the file is Roboto bold.
So there you go.
Alrighty, there we go, we've got our outline.
And I think that looks pretty sweet.
But let's go ahead.
And now let's start drawing stuff onto the board.
So we will get to sounds pretty early in this project.
And I will kind of go over how those are used.
Because obviously sounds are super important.
But first, I'm going to set up a function that I'm going to call draw grid, and it's just going to kind of draw all of the static things onto the screen.
So I'm going to do that right below my screen dot fill, is I'm going to call it draw grid.
And then then we're going to come up in between, like I said, the variable library and the main game loop.
And I'm going to define this variable draw grid, and we're going to start building this out together.
Okay, so let's start with draw grid and just kind of think of the space that we're going to have in this game.
So I'll start I'll call kind of the left menu, left box.
And that's if you've ever seen like a beat layout, like that kind of app.
That's where you have the instruments and sometimes you have the ability to like turn tracks on or off or adjust volume of the specific instruments.
So we'll create kind of a left menu I'll call it left box and We'll put it on the screen, and we'll make it gray.
So that's why I call that color in the beginning.
And then we'll start at the top left corner.
So at the very corner, it will make it 200 wide.
And we'll make it the full height of the screen.
So these are the four arguments, you give rectangles, x and y starting coordinate in the top left of your box, and then width, and then height.
And then after that, these are now optional.
So this would just give you enough right here, let me see if I run it should work, we get this left box, which looks fine.
But now if we add one more argument, we're going to say how wide we want the edges to be, which is going to make it a hollow object.
So it's going to have a width of five.
And I think that looks better as a left menu.
Personal preference, you can leave it totally thick, if you want.
But then let's also add a bottom menu, which I'll call bottom box, and we're going to pi Game dot draw dot rec, this is where we're gonna put like our player controls, like start and stop the loop of the game.
So like play pause, I guess I say game, you understand it's an app.
But we're gonna put like play pause, and then also like save and load.
So the options to save your B or load in a previously saved beat, or adjust the speed, or how many beats are in your app total, will put them in this bottom box.
So we're going to call that screen, gray.
And then for this rectangle, let's put at the bottom.
And actually, let's make it just 200 high.
So height, minus 200.
So that's going to be the starting position.
And then we'll make it for with the full width of the screen and 200 high.
And let's make this hollow with five as well.
And what you'll see if I do this, now we're going to have this kind of weird rectangle, maybe you like that look, maybe you don't, I'm gonna take my left box, and I'm deciding I'm gonna stop it 200 High as well.
So now we won't have that like criss cross overlap in the bottom.
I think that looks pretty good.
So we will move on.
The next thing I want to do is I want to start creating the beat.
So we are going to make it so that it's adjustable, how many boxes are in here.
But just to start, we're going to just set it up so we can get something on the screen.
So what I'll say is, I'm going to create a little empty variable here that I'll call boxes, just like that.
And I'm gonna create a little colors library.
So colors equals gray, white, gray.
And some of this stuff, we're not going to touch for a little while.
So if you don't want to follow along line for line, I guess you can skip that for now.
But we are going to come back to it.
Sorry, gray, white, gray.
So we're gonna do those.
But now what we want to do is thinking of a drum kit, the first three most important instruments are hi hat, snare and kick.
So what I'll start doing is kind of creating space for those.
So first thing I'm going to do is I'm going to call it hi hat.
And now we call that label font that we have.
And it's label font dot font, or sorry, label font dot render, we already defined it as a font, and then you give it the text and for the hi hat, we will just say hi hat, that should make sense.
And then the second one is like anti alias as a Boolean.
It's always true in my experience, I don't actually know.
I don't know a scenario where it wouldn't be.
And then later when we have the ability to turn a channel on or off.
So you set up a beat and you want disable the hi hat, we'll make this a variable.
So we will be coming back to this.
But for now I'm just gonna make it white to not overcomplicate the early steps of it.
And we're going to draw it on the screen.
So screen dot blit.
And you give it what text you want.
So we want high hat text to get drawn on the screen.
And that needs an X and Y coordinate.
And I'm gonna move it a little bit down and a little bit right from the top corner, even though this is our first one.
And so this should be all we have to do to see the text hi hat.
So I think that looks pretty good.
And now let's go ahead and do let's just basically take this exact stuff, C Ctrl V, and let's do snare and kick.
So, hi hat txt.
We'll do snare Tex, next, snare and snare text.
And then what we'll do is we'll move it down 100 So I believe we made the game 800 High, the bottom menu is 200 high and we're going to put a total of six instruments in here.
So we're going to do a hi hat, a snare, a kick drum, crash cymbal and then we'll do like a floor time and we'll do a clap.
Those are kind of the six most basic beats.
If you want you can grab Your Own soundboard.
And we'll go over that a little bit later.
And make whatever sounds you want, you can make as many instruments as you want.
I'm kind of giving you the backbone of how to set it up, though.
So that'll be snare and hi hat.
Let's go ahead and do the next two, which will be we'll call it kick, because it's a kick drum, but you can call it bass if you want.
And what the heck, we'll say bass drum on the text, that's probably what people are more familiar with.
And we'll say kick text.
And let's do after kick, let's do the crash cymbal, and crash, and crash text.
And we're moving these down 100 for each of them.
So 200 300.
And we're just going to have two more.
So we have bass drum and crash.
And then we are going to want to do the clap.
And the floor tom.
And floor tom.
And so we'll go to 334 3530.
Now, let's just draw this and see.
Okay, so that looks pretty good.
I think what would make sense is putting lines in between them to, to kind of delineate those.
So why don't we draw those as well, after this text, we'll just do for i in range.
And I think we want six because there's six instruments.
So for i in range six.
And we'll do this Pygame dot draw dot line screen will make it gray.
So it blends in with the edges.
And we'll start it at zero.
And then for height, we'll want it to be I times 100.
So I times 100.
But since we don't want the first one to be at the very top, because the box already starts at the very top, and for for loops, it's going to start at zero, and that's going to go to five, that's just kind of how for loops and Python work.
They're not edge inclusive for the number six, so it's going to do 012345.
But we want these lines drawn at 100 200 300 400 500.
And I guess we don't technically need 600, but it shouldn't affect anything.
So starting position will do, I will do zero, and I times 100 plus 100, I think that'd be a little better.
Or you could just add one to range, I guess that doesn't matter.
All right, and then end position, we'll want it to go.
Let's see, to 200.
Right, that's how wide we made that menu.
And then we want the same y coordinate, so it's a vertical line.
Let's copy that.
And put that in here.
And since the edges of the menu are five, let's make these lines five as well.
And let's see if that gives us lines in between all of our instruments.
I did something stupid, I don't know why I have this square bracket in here, you do not need a square bracket if you are drawing a line.
So the line arguments are the screen the Color Start position as an X and Y to coordinate tuple and position as a to coordinate tuple.
And then line thickness.
And let's see if five is a little too thick.
That's okay, let's see if it looks better as three maybe since these aren't the outer edges of our menu, maybe that would look better.
Yeah, I'd like three more.
You can do whatever you want, if you want thicker, make it thicker.
But that's good for me for now.
And now what I think we want to do is we want to start considering how this game is going to work how this app is going to work in terms of the beats.
So we're going to have a variable that will set right now in the beginning beats.
And we're just gonna make it equal to eight.
That's a very simple basic setup that we could do.
But we need to use beats in this in this app, to check how many boxes we need to draw for each instrument.
So to do that we do for i in range, and then beats.
And let's create a variable that I will call instruments.
And we'll use this a few times throughout just to check how many rows there are.
So I guess you could call this variable rows if you want.
I'm going to say instruments because there's six different sounds that we have in here.
And I'm also going to instead of frying range six, I'm going to say for i in range instruments.
But the reason I'm doing that is because we're creating a grid basically for ion range beats.
And then for J in range.
And this is instruments.
And so this is another way hopefully if you have the interest in creating this game, so the or app whatever I'll say game probably throughout this because the module is called PI game and I do so many games aims.
But so if you want to add more instruments, we're creating it now to where all you'll really have to do is adjust how thick each instrument should be.
So you could make it to where it was a function of that 600 vertical space that we have, you could give me 50 instead of 100, and then have 12 instruments totally up to you.
But we're creating nested for loops here.
So for Iron Range beats, and then for J in range instruments, what we'll do is we will say that, we're going to draw this rectangle equal to pi Game dot draw dot rect.
And we'll put it on the screen.
And for now, I'm going to just make them gray as well.
And we are going to make the, let's see, we want to make the thickness of them.
I'm trying to think here, I don't want to misspeak, we want the thickness of them to be we want the starting position to be AI.
So that'll be our b, that's going to be for the x the starting position will be Ai times, and then we will want the total width that we have available for beats, which is the width of the screen minus 200.
So we have this width of the screen, minus 200, put it inside parentheses like this, and then we're going to use something called floor division.
And we're going to floor divide by the beats.
So this floor division just makes sure that it's an integer, because for x&y pixel position, I guess it's not exactly pixel position, but it has to be an integer.
So like, let's say this right now would be 1200 divided by eight, because that's how many beats we have.
This is going to start it at 1200 divided by eight, which is like 150.
But if for some reason it was like not uneven division, this would make sure that it stays an integer.
And then we'll want to move it a little bit to the right, initially.
So as always, as I said, with for loops, this is going to start with zero, but we don't want it to start at zero, so we'll add the first 200 to it.
And then I guess it's a five thick rectangle, so we'll add the first 205 to it.
And this is just our x starting position.
So this rectangle is going to take some math, so bear with me.
For the whi starting position, it's a little easier because we don't have a top menu, so it'll be j times 100.
And here, it's actually okay, that starts at zero, we'll just do plus five, because we're going to give it a width of five as a border, excuse me.
So actually, we don't need a border on the top, it can be right up against the top, and this one will be okay as well, right up against that menu.
So we'll do just plus 200, and then j times 100.
And then for the actual rectangle, we will say, excuse me, for the actual width, we want it to be the again with minus 200.
And this can be really important to make it to make it adjustable to where it works for any number of beats because a big function of our app is going to be that it's adjustable in that front.
So again, just do the width minus 200 floor divided by the beats, this will always give you the largest possible width, but still make each box even.
And then for the height.
Since we have six instruments, we could do it this way.
We could do height divided by instruments divided by instruments, but it's not exactly height divided my instruments because we have a 200 width 200 height, bottom menu, so it would be height minus 200 divided by instruments.
And you should really make this a floor division as well.
But because this is 800, and we know that 800 minus 200 to 600.
And we have six instruments, this is effectively the same thing as putting a 100 here.
So if you want to just make the height 100.
Go ahead and do that.
If you understand what's going on and you want to do this math, because you want to be scalable again, then do that by all means.
Okay, so let's see what we have to do here.
Because this format doesn't look quite right.
I think I just need to close the parentheses.
And I'm going to zoom out a little bit here because this line is a run on.
So let me just copy that into a new row.
There we go.
And let's make this a width of five and a rounded rectangle.
Those look good statement founded.
Let's see why we're getting errors here.
I probably just did something silly on the formatting.
Oh, I have too many close brackets.
All right, I'm not going crazy.
Sorry for a little bit of troubleshooting.
It's just sometimes you put one too many parentheses in there.
So let's just double check real quick for these rectangles because we're doing some advanced math here.
But once it's set up properly, it's going to immediately be scalable to the whole app.
So we are starting it at the beat.
So if there's eight beats, it's going to start at 200.
And then it's going to calculate how much room it has on the screen.
And it's going to automatically update to take as much space as it can.
And then it'll do the same thing based on how many instruments and we're going to make it a rounded rectangle, which is what the second five is for.
And we're going to make it five thick, so that it should be hollow rectangle.
Now, let's see, because we should get eight beats, fingers crossed, that's not bad, we get, we get eight beats right now per instrument, and they fill the whole screen.
And that looks pretty good right there.
So you can see we're getting kind of the rudimentary shape of this fleshed out, which I think looks pretty good.
So let's see, we'll come back and we'll improve this style later, I think what's going to be important is we start taking a look at how to get this kind of functional, because that's going to be really satisfying, if we can start actually implementing that a little bit sooner rather than later.
So what I think we want to do, because you'll remember at the beginning of this, I created this empty list for boxes.
Well, as we go through and create all these rectangles, what we want to do is add some information to this list I made called boxes, because we need to bring that information back from our function, so that we can check if these things are getting clicked.
So what we're going to do is we're going to every time we call draw grid, we're going to empty out the boxes variable right here, we're going to make it empty.
And then we're going to draw all of these rectangles onto the screen.
And then we're going to return some information in this list.
So what I want it to be is you can kind of think of it of it as a tuple.
Where inside the tuple, one of the two arguments is another tuple.
So if that's too confusing for you think of it this way, we're returning a couple of things, we're returning the rectangle of each beat, but then we're also returning an X and Y coordinate for it.
So we're returning what b it is, which is the eye and then we're also returning what row it's in, which is the JE and then we're actually returning the full rectangle.
And the reason we're doing that is because we're going to use that for the collision detection to see if it was clicked on.
And then what we will do next is we will just return that boxes variable we just talked about.
So when are we called Draw grid.
Let me reformat that just so it likes how many spaces.
So when we call draw grid down here, we need to get boxes back from it.
So let's go back down to our game loop.
And where we get boxes is right here.
And what we need to do is use that boxes list to check and see if we clicked on any of the boxes.
So that's not too bad, we just have to add some new collision detection.
So what we do is we come down into where we have this if event dot type equals pi Game dot quit.
And we do if event dot type equals, and then this one is going to be pi Game dot mouse button down, which is what is if you're clicking the button down, and haven't yet released it, so there's mouse button up and mouse button down in Pygame.
And that's what we're going to start with.
And we're going to create a loop that's going to iterate through the entire list.
So we'll say for i in range, and then the length of boxes.
And the reason we're making it the length of boxes is that list, which also means actually in the very beginning, this is important thing, anytime you create a variable.
Even if it's one that you get from a function, if you're going to use it in your main loop, you need to have it initialize somewhere, or it's going to say that it was referenced before it existed.
So for i in range, and then the length of boxes, and the reason for that is every time we update the total beat, the total beats, whether it goes from eight to 12, to 16 to 20, whatever, that list is going to get significantly longer or shorter.
And so this has to be scalable to check that whole thing.
So for i in range length of boxes, if boxes and here's where we have to be very careful about the way that we address each item in there.
So boxes, and I so that just means we're going through the list of boxes that we defined, and we're checking each box at i which is going to call up the whole tuple so rectangle and then coordinates and then we check zero.
So that's reference Seeing the rectangle that we stored in there.
So the reason we did that is because now we can use PI games built in collide rect function, which is this super useful, super useful built in tool, which checks if an X and Y coordinate, which in this case will be the mouse.
And it's checking to see if it collided with a rectangle.
So in this case, if collide rect with event dot pause, so event dot pause is the position at which the mouse was when the mouse button down occurred.
So the position that our mouse is in when we click, and if it collides with it, so this is already right here going to check if we clicked on any of the rectangles that we just defined, so we're creating a really powerful function.
And we're going to say coords is equal to boxes at i, and then one.
And the reason I'm doing this is because it's a little bit easier than referencing the x&y coordinates as boxes, one, zero, and then boxes one, one like that, this is just going to give me this temporary variable called coords, which we're going to use right below to track whether or not something has been actively clicked.
Okay, so let's go ahead and do that what we're going to do.
And here's where we're going to need to create a new list.
Because we are going to take clicked at coords.
And I guess, actually, we have to be careful about this, we put the i and then J, and J is what row it's in.
So actually, we're going to want coords one, and then chords zero.
And I think I missed a box.
There we go.
Okay, and we're going to want to set that equal to the opposite of whatever it was.
So let's go ahead and create the clicked list.
And the reason I say list is because this is what's going to keep track of what variables have actually been of what bits have been selected or not.
So at the very beginning, I'm going to create this list.
And we're going to do it in such a way that we define what's basically a full list of negative ones.
So I'm choosing to make negative one mean, it's not currently active, and one means it is currently active.
I think that's the easiest way to do it.
And I think you'll see why in just a second.
So let's do it this way, let's say clicked.
And this is our list of what beats are selected and what ones aren't.
And we'll say clicked for underscore in because when you're just doing it right here, you don't really need a variable like AI or something to reference.
So we'll just do for underscore in range beats.
So this is going to create initially, a list that is that size, and so for underscore and range beats, and then it is going to be that for underscore in range instruments.
Okay, so this is going to create a list as soon as the game starts up that because beats initially is eight and instruments is six, it'll be eight negative ones in one list, and then there'll be a list of six rows of eight negative ones.
So it creates this really useful array, essentially, a list of lists, that's going to initially be all negative one.
And the reason I'm doing it this way is because then when you click on a box, we can set it equal to negative one of itself, so we'll multiply it by negative one.
So if it's a one, it'll become negative one, but if it's a negative one, it'll become a one.
And the reason we're going to do it that way is we can use that list to draw all of the active screen all of the active rectangles.
So if they're a one, that means they've been selected, and there'll be green.
So this is a really versatile way of setting that up.
But what it does mean is that we'll have to pass the clicked list into our draw grid.
So we'll just come up here, draw a grid, and we'll pass in the clicked list, which is fine.
It's not like that's an inconvenience.
And what we'll do is we'll come up and we will say, now remember, I said we're going to check for each of these rectangles, and we'll adjust the color based on whether or not they're active.
So I'm going to add a few more colors here.
I'm going to say green is equal to R, G, B, Z.
It's just all all the greens 0255 zeros.
And actually that'll be playing for now because we're just going to make it if it's active, then we will have it draw green.
And we need to make sure we're receiving the argument clicked.
And sometimes inside of your function, it's not a bad idea to use a different variable name, like I know I used boxes, but because we totally reset it every time, that's not really a problem.
But we're not overriding clicked in the draw function, we're just using it.
So what we'll do here is we'll come down and say, doop, doop doop boxes equals colors.
Okay, so let's do this for i in range, beats.
And then for J and range instruments, let's add something down here, that's going to say, if clicks at, and this is going to be again, j, then I, because the first item is going to be what row it is, and then AI is going to be what column it's in.
And we'll say, if it's equal to negative one, then we'll have our color that we're currently using be gray, because it's not active.
But then what we'll say is else and you could say l f.
And you could check if clicks is equal to negative one.
But then we'll say else color will be equal to green.
And now I'm actually going to keep this one because this rectangle is essentially the outline of the rectangle.
And there's no reason to mess with that exactly.
Other than I just want to put a few more stylistic things in here.
So we don't need this second one.
Well, let's make the colorful one, the rectangle that we actually referenced, so we'll leave this alone down here.
But then what we'll do is we'll say Okay, on the screen, at our color, and then we want this one to be solid.
So if you want it to be a rounded rectangle, which I think would look good, but you want it to be solid, then just make this argument to zero, and that'll make it solid.
Now let's see what else we can do.
Since we're in here, I think maybe I'd like the idea of doing like a gold, just to upgrade our style a little bit.
So since we're here, and we just made a green, I'll also make a gold and I pulled this RGB ahead of time to 12 175 55 to 12 175 55.
If you have a color in mind that you'd like to use, just Google RGB value, and then the name of your color, and you'll be able to select through everything on the internet.
Finding RGBs is not hard.
Okay, so now let's go ahead and just essentially move this rectangle that we just made, that is a specific color, let's move this one inside of the parameters of this outer rectangle.
So here's where we'll scoot them around, we'll move this one down five, and in five, and then we'll make it this width, I think minus 10.
So we're basically putting it inside the frame that we built before.
And we'll make it this height minus 10, as well, since we're putting inside a frame that's 10 by 10.
All right, and we'll leave this let's make this one, maybe black.
And let's put this gold frame kind of inside of it.
So I'm doing kind of a three tiered effect.
And this is purely for style.
So sorry, if you didn't like this detour, but I think it really adds to the look of the project.
And what we'll do is we'll make this gold one, a formal a full five by five, and then we'll put a black like wire inside of it.
So let's just go ahead and load this up before we do too much and lose sight of the project.
But what you're seeing is none of these have been clicked.
And so what I have currently is a gold rim of five with a smaller only two thickness black rim around each of them, but it gives a really cool depth to it.
Now let's try clicking.
OK, we got an error.
object must be wrecked style event.
I totally agree.
Let's take a look at what we're doing here.
So we are passing in the rectangle Pygame dot draw dot rect Yep, that should be right.
And then we're returning boxes to do four boxes dot append.
That looks good.
Oh, silly mistake because I used collide rect in this position but it needs to be collide point because what we're checking is if the rectangle at boxes is zero is colliding with our mouse click which is just a point so this needs to be collide point not collide rekt.
Let's load it and try to click some now.
Okay, so there we go.
We get hi hat green, which is pretty sweet.
And I can select multiples.
And now can I turn it back off? Yes, I can.
Let's see if I can select them kind of from all over.
Yeah, so that's perfect.
That's the functionality we want.
And now you're probably aware bear that we do not yet have any sort of movements across the board to actually play the notes.
If we've selected them, and I promise we're getting close to actually having sound, which is really the fun part of it, okay.
But what we need to do is we need to do some math to essentially calculate, how long should each beat be.
And so what I'll do is I'll come down here, and I'll create a variable.
And I'll call it beat length.
And what is going to be equal to, and this is where I mentioned right at the beginning, if you use the different frame rate, then this needs to be adjusted a little bit more oops, bpm.
So we haven't created a variable yet called BPM, but that's going to be another part of this game.
So we'll say beats per minute is going to be 240, initially, which is four beats per second, which is pretty fast.
But that's what we'll use right in the beginning.
And so that means the length of each individual beat as our game is seeing it is going to be 3600 divided by BPM, if you have to think of it this way, you can think of it as your frames per second times 60, because in each minute, there's 60 seconds, right? And then that's if you're using a frame rate of 60, that's 60 times 60, which is 3600.
And then we're doing floor division to make sure we get an integer of how many beats per minute we want.
So this is how many clicks per minute, essentially, how many loops per minute, this while loop is running.
And so each individual beat is going to be that number divided by how many beats per minute they're supposed to be.
And so what we'll do is we'll say, if playing, we'll do it that way.
So we'll create a variable.
And for now, we'll always be playing.
So right in the beginning, we'll set playing equal to true, but later when we put pause functionality, and it'll be nice to have a variable that controls whether or not we're playing.
And so we'll say if playing, then what we'll do is we'll create a new variable, if active length, so how long has the beat that we're currently on, been active.
And so right when the game starts up, we'll initiate initialize that one as a zero.
And so active length is equal to zero right when we start so if playing while playing, if active length is less than beat length, then we want to just add one to active length.
So we have this variable active length, where we track what beat we're currently on.
And we're just going to add one to it every time that we're not at beat length.
But then what we'll say is else.
And so this means that the beat has just reached how long it's supposed to be.
So just for easy math, if we said we wanted 60 beats per minute, once every second, we should move to the next beat.
So we'll say else, and then that would make active length equal to zero.
And now we need to check if we're at the very end of a cycle, and we need to go back to zero or if we can move on.
So what we'll do is we'll create another variable, and we'll call it active beat.
And we'll say if active beat is less than total beats minus one, so that means we're not yet at the very end, then we'll add one to active beat.
And it's given me oops, active beat, not active length.
And it's given me a red underline because we haven't initialized that one either.
So right in the beginning, we'll call active beat one.
And you don't really want to start with zero because in even though in code programming, you pretty much always start with zero, for a beat, it doesn't really make sense to be at zero at any point, you're always on beat 12341234.
Okay, so active beat, we'll add one to it.
And then we'll use this variable that's just going to be an on off variable be changed.
And we'll set that equal to true.
And we're going to use that in just a second to actually play the notes on that beat.
So else, then we'll just add, then, whoops.
Else meaning else against this if statement if active b is less than or equal to beats minus one.
And so we'll say else because in theory, if the beat was on like 24, or 26 out of 30, but you decided to reduce the total number of beats, then it wouldn't work to just say, you know, else if active beat is equal to beats, we want to say else covering any scenario, meaning we're not at the end of our loop.
So this is saying we've gone too far.
Set Active beat back equal to zero, but beat changed is still going to be equal to true.
Okay, and so, let's go ahead and I think that should be all we need to do to get it moving.
Let's go ahead and same beat, changed equals true right in the beginning.
Because technically, as soon as the app loads up, you would want this on.
And now we have to do something with that active beat variable, we want to actually draw something on the screen showing what beat we're on.
Okay, so what we'll do now is we will just say, we want to pass in what beat we're on.
So we're already, we're already using.
Let's see, yeah, we're already using the Click Variable from the outside world.
So we'll just come down to clicked.
And we'll draw active beat as well.
All right, and I want to use a new color for this one, so that it kind of pops out of pops out at us.
And I'm going to create like kind of a vibrant, not exactly neon blue, I'll just call it blue, because it'll be the only thing in my app, I'll make blue.
But to get this color I'm doing, it's pretty much like a teal or an aqua, it's going to be a lot of G and B.
So it's, it's like a neon blue, but I'm just going to call it blue.
Anyways, we come into our draw grid function.
And underneath everything else we're drawing, let's draw this new thing that I'm just gonna call active, and it doesn't really matter, it's just so that I know what I'm drawing, because by the end of this app, there's gonna be a lot of code all over the place.
So that's just for me, I'm gonna put it on the screen, we're gonna make it blue.
And then we need to start thinking about this rectangle.
So it's basically a moving rectangle that shows you what beat you're on.
And, to do that, we'll use the beat variable that we're passing in times, and then with floor divided by 200 minus 200.
Sorry, this bits should be familiar to you by now.
Divided by beats.
So we're talking about where we want to start that beat variables 12345678.
So you think about it, when it's a one, we want to start at 200.
So it's going to be one times this.
And then plus 200.
So we need to scooch to plus 200.
And so this means, actually, this might be 200.
Too far watch to see with my storage.
We'll see when we load it up.
Because it may be designed to start from zero.
I wonder if that would be a better way to do it.
I'm not worried about right now.
That's something we can tweak later.
And then let's see the why starting position, let's have it start at the very top of the screen and then go all the way down to the bottom of the instruments.
So then how why do we want to be well, this one's easy.
It's just with minus 200, and then floor divided by the beats.
So that is just saying we want this rectangle to be exactly one beat wide.
And then we will make it as tall as the instruments times 100.
So there's 600 Hi, basically, it's just a rectangle, that's going to be surrounding the entire active beat.
And those are the four arguments the rectangle needs, except I put the bracket in the wrong spot.
There we go.
And then let's make this we certainly don't want this to be a solid rectangle.
Let's make it a rounded rectangle of border with five and cornered radius of three.
And let's just see if we correctly have a beat moving across the screen.
So I actually think that's pretty sweet.
It's it is starting in the right spot, it is going to the end and then immediately goes back to the beginning.
Currently, it's not doing anything with different sounds, but that is the next step.
So let's go ahead and finally the thing you guys have been waiting for.
Finally, let's implement some sounds.
And for this, I'll say I have a folder prepared called sounds.
And I have these six wav files in here.
I also have a nother folder in there with some more wav files that I'll talk about later.
I just wanted to show how you can switch between kits.
But we'll get to that way down the road for now.
To do what I'm doing you'll need to get six wav files of the sounds.
I use the free online download that I'll leave a link to hopefully are mirrored put in the video right here.
If not, I'll make sure there's a link to the website in the comments below.
And hopefully I talked about in the intro of this video as well.
tons of free sound kits on there so you can download one that works for you just to be able to follow along with this or honestly you can make the noises with your mouth and record record them but you will want to use wav files mp3 these have some issues with mixer and they don't work as well in my experience, okay, so just make sure you've got this sounds folder and clap, a crash, a hi hat, a kick, a snare and a Tom, if you want to follow along directly, and I'm just gonna make this little area that all say load in sounds.
Now, we'll start with the hi hat.
And we will set that equal to mixer.
So remember we called Pygame dot mixer right in the beginning, we imported it.
Now we're going to use it and to do that we set up this mixer dot sound.
And then all we have to do is give it the file it lives in.
So sounds and then backslash.
And I just call it hi hat dot wav.
Okay, so just like this, and we're going to copy that.
And we're going to make six of them here.
So we'll say hi hat, and then snare, snare.
And then we'll call it kick, and then we'll call crash, in then clap.
And then Tom.
And then in the sounds, locations, we'll do snare, hi hat do kick, make sure that your names match up exactly to what the actual files, say over here.
I always recommend, if they don't download is something pretty logical, consider renaming them to something that's a little easier, a little more logical.
Okay, but just like this, and if you do have a TTY, or a special character that looks like an escape character, like a backslash, N for any reason, just make sure to do this double backslash, because this is basically what you need to do to get a backslash interpreted as a literal in your string.
You don't have to worry about that too much.
But if you do get anything funky, where it like thinks it's an escape character, just do those DOUBLE backslashes.
And that should work for you.
Okay, so now we're going to come down to where we did draw grid.
And we're going to put in something that's going to use that beat changed functionality.
And so every time the beat changes, we want to play the notes.
So did you do for iron reigns, I just want to make sure I put it in a good spot.
screens for Iron Range instruments, draw a line down in here, boxes, draw the grid.
So what we want to do is say if beat changed.
And then, so if the beat changed, we'll call this function play notes.
And this is just going to play the sounds that we just created based on the beat changing.
And then immediately, we're going to set beat changed equal to false.
So this is how, even though this code the outside code, this while loop runs 60 times every second, this loop only runs once per time that the beat changes.
And that's how we control total number of times that the beat that the sounds get played.
So that's that.
Now let's go into let's go above draw grid.
And let's define the play notes function since the sounds are right here.
So we'll say define play notes.
And this one's pretty easy.
It's just for i in range, and then the length of our clicked list.
If clicked at i, and then the active beat, so that's all we have to check is if clicked at i, which is going to check each row.
So each instrument in our clicked list at the active beat.
If it's selected as a one, then we're just going to check what i is equal to, and then play a different sound based off of that.
So if is equal to zero, we want that sound that we created.
Just do hi hat dot play just like that.
That's the whole thing you have to do.
And then we'll do Ctrl C Ctrl V.
And even though this one is a little bit you know, monotonous I would say it's not too bad.
And probably outside of putting these sounds in a list.
And then referring to a specific like, item index of the list.
There's probably not a faster way to do this.
Other than just going through and making sure you've got the order right for your stuff.
Crash and then clap.
And then Tom.
Actually I'm not sure that's how we drew it is it hi hat snare kick, crash clap and then Tom I think okay, that is yeah, if i is equal to five then we'll do Tom dot play.
And this right here what we just set up super fast, super easy, is all you have to do to get the sounds playing or It should be.
So let's go ahead and just load this in and see if we can get just some sounds.
I'll try this hi hat.
And I'm really hoping I left sound on recording the computer here.
So hopefully you can hear that hi hat going.
If you're following along, hopefully you're getting this now let's play it.
All right, maybe it's just me.
But I think the fact that we're here already is super cool.
And you can turn stuff on, you can turn stuff off.
And try playing around with your different sounds, once you get to this point.
All right, it's so addictive, I could stay right there forever.
Once you get to that point, that's a really good time to check that the sounds that you imported are actually the sounds that you're hoping to get because you can change those sounds down the road for sure.
But that's kind of your first way of knowing whether or not you have sounds that you're going to be happy with going forward.
Okay, so there is one thing that I would like to do on the mixer.
And it's because the default for your mixer, the default for that, when you load it in from Pygame is it has a total of what's called eight channels that it can play on.
So eight total sounds technically that could be ongoing.
But some of those wav files like the crash cymbal, actually take a couple loops to finish.
So in theory, you could run into this problem where you run out of sounds, and so it has to pick what sound it should let you play because its default is to only have eight.
The way to get around that is super easy.
You just do pi Game dot mixer dot set, num channels.
And then I think general rule of thumb is that the number of instruments if you give them each three channels, there should be no issues here, regardless of how fast you start playing.
Unless you're up to like 600 beats per minute, then maybe you need to beef this up.
But the reason the eight is the default is because in general, if like you have a video game going and you have more than eight sound effects at once, it's just chaos.
But like for a soundboard, as long as you're picking sounds that sound okay, together, having a lot more channels is okay, so you could do instruments times four, if you really wanted instruments times three has worked fine for me in the past.
So we're gonna go with that.
So that's pretty cool.
I think we're kind of at the point, we want to start adding some player functionality to this.
So like, Let's do play pause, because that should be an easy one.
And then we'll start doing it to where you can add more beats, and you can add more beats per minute, or subtract beats per minute.
And then we'll add the functionality to be able to turn on or off a specific channel.
And then we'll start looking at the ability to save and load files, which is a it's a lot that we got going ahead of us.
So let's just soldier on.
If you are enjoying this video, I think you've made it this far already.
Let me just say please leave a like on the video, subscribe to the channel, it would mean a ton to me, I hope you've been enjoying the content, I try to roll out high quality content like this all the time.
And the support means a lot.
If you have any questions about what you're seeing or want to see something specific in the future, be sure to leave a comment letting me know about it.
Without any further ado, let's soldier on.
Okay, so let's do a play pause button.
And we'll just come down below draw grid.
And we'll just add a rectangle that we're going to draw right down here.
I think it's easier than drawing it on the I think it's easier than drawing it in the grid.
But if you disagree with me, that's fine.
Just draw it wherever you want.
So I'll say lower menu buttons.
And I'm going to create a little section in my code for this now.
And I will just call this button, the play pause button.
And I will say Pygame dot draw dot rect.
I'll put it on the screen and I will make it gray.
Because it's on a black background.
So gray will look pretty good.
I'll move it off from the left by 50.
And then I'm going to raise it up from the bottom by 150.
So it's still squarely within that menu.
And they'll make it 200 wide and 100 tall.
And that should be a good button looking object.
We'll make it solid.
And I'll make it a rounded rectangle, which is kind of normal for buttons.
And I will just yeah, let's do some text to just let everybody know.
So I'll say play text and we will set it equal to the label font dot render.
And let's give it the text of play slash pause and let's make it true.
And let's make The Text white, and let's put it on the screen.
So screen dot blit, play text, and then let's put it inside that button by a bit.
So 70 and then height minus 130.
So it should be pretty close to dead on to the middle of the middle of the button.
And now let's add a little check to whether or not we're playing or not.
So if we are playing, then we'll have play text to here.
So let's do a new font, I'll call it medium font, because it's not exactly going to be small.
But we are going to come up to where we defined our font the first time.
And let's create a new font, medium font, and it's going to be the same.
It's just going to be smaller because I've got this button, that's going to say play slash pause on it.
I'd like to say underneath it, whether we're paused or playing.
So I don't want to be small, I want to be super easy to read, but it shouldn't be the feature of the button.
So I'll just make it 24.
We'll see how that looks.
And maybe we play around with it later.
Okay, but yeah, so we'll say, alright, playing text equals medium font dot render.
And then it is going to say playing if we are playing, playing true.
And we'll make this one I'm still inside the string, anti alias true.
And let's get a new shade of gray.
In our in our kind of colors library up top.
And in general, the closer to black, your gray is the darker it's getting.
So we have this regular Gray, I'll say dark gray, and it's going to be just 50 5050.
So black is 000.
That kind of light, normal gray we have is 128 128 128.
So the lower the numbers on your gray closer to black higher numbers lighter, just neat little gray tidbit for you.
Okay, so we'll say play text is equal to playing if we are active, and we'll say that it is equal to, so we don't need if playing this is just else now.
Else, it'll be equal to paused already.
And let's see, let's put it on the screen.
And let's put it underneath.
So we'll take this screen up blit Ctrl, C.
And right there, and let's put it height minus one, three, let's put 30 pixels lower on the screen.
So height minus 100.
Now it'd be 100 pixels off of the bottom of the screen.
And it'll say playing or paused.
But right now, we're not actually handling whether or not it's been clicked.
So let's figure that out here we want to do inside of our mouse button clicking code, let's add a second section for click up.
So in general, if you want something to only happen once, then it's usually a better idea to do Pygame dot mouse button up.
Because if you're holding the button down, then it could technically like do it multiple times.
And you don't really want to mess with that.
So we'll go to if event dot type equals pi Game dot mouse button up.
And we'll say if play pause dot, and I'm not gonna get wrong this time collide point.
There we go.
collide point with event dot pause, and playing.
So the reason we need the and playing is because if it's if it is playing, then we need playing to be set equal to false.
And actually, what's probably a better way of doing this is rather than an playing there, it will do if playing in here, playing equals false.
And then we'll say L if not playing.
And the reason you don't just want to do else here is because if it was playing, you would come through and then it would be not playing and then we'd say else and then it would see that it's not playing and immediately set back equal to playing.
So you need to do an L F if you do it this way.
L F playing equals true.
And that should do it.
So we already have the active length like checker stops if we're playing.
So let's see if our pause button works.
I don't think I updated the text.
Okay, hang on a second play text medium font dot random.
This is play text to not just play text.
There we go.
All right, that looks sweet.
We've got playing down there.
I pause it you can see our blue rectangle stops and then it keeps going.
I think that's great.
Okay, so let's see if I pause it and I set up a beat.
And I'm just doing kind of a generic rock beat will end with a crash.
posit, and let's add some floor times because those are cool.
So that's, that's awesome.
I think that's a great start, I think maybe the next thing we should do is make it to where you can add more beats, more beats and more bpm.
So that's kind of that's going to be kind of complicated, but just bear with me because I think we've created a really useful backbone for this project where actually everything is going to scale really well, we just have to implement it.
And we have to be careful about getting all the details, right.
Okay, so let's go ahead next.
And I think let's add the BPM stuff.
So we have lower menu buttons, we're in this.
We're still in this section, for sure, lower menu buttons.
And we'll do BPM stuff here.
And I just find it helps to split it up with those comments a little bit.
And so first thing we'll do is we'll make a BPM rectangle Pygame dot draw dot rect.
And we'll put it on the screen rect hoping on the screen, we'll make it gray.
And we will use more or less the same size rectangle.
So for this one, we'll make it 300 To get it 50 pixels away from the last one, but it'll still be height minus 150, we'll still make it 200 wide, and we'll still make it 100 high.
And we will still make it solid.
No, you know what, because this one is not a button.
Let's make this one hollow.
This one is just displaying how many beats per minute, and then the beats per minute, add and subtract buttons will be to the right of it.
So let's make this one hollow.
And then add some text we'll call BPM text.
And that will be the label font now.
Now we better not do label font, because it's a lot of text actually.
So medium font dot render, and then we're going to spell out beats per per minute, there we go.
Okay, and let's put it on the screen, inch true white, and then put it on the screen screen dot blit.
And this is going to be the BPM text.
And then for position, we don't want to move this one in too much, because beats per minute is kind of long.
So we'll do 308 Just to get in by a little bit.
But we'll still do the height minus 130, just like that.
And then what we'll do is we'll do a second text that's actually going to show BPM text to, and that's going to be the label font, because that can be big, this is going to show the actual beats per minute.
So not just the text telling you what it is.
So this will be label font dot render.
And then you could make this a formatted string if you wanted to.
If for some reason you want to add anything other than the beats per minute variable.
I'll do it that way just to show it could be done.
So in theory, you could say like, BPM, colon and then BPM if you want it to, but I'm going to put this below the beats per minute text.
And again, true, and we'll make it white.
And let's put this on the screen screen dot blitt, the pm text to and let's put it just underneath.
So what would make the most sense, probably 373 70.
And then I'd say that height minus 100.
Maybe where we put the last second line of text.
Let's just see how that works.
And let's check this out.
So beats per minutes 240 I'm a little surprised because I thought I was trying a rectangle there.
BPM RX green Gray 300 Oh, I did height minus 1500.
We want height minus 150.
Yeah, that looks a little better.
Okay, so that's cool, but we can't just yet can posit it still, I just think what we've done so far is really cool.
So sorry, if I enjoy it, this is like the most fun project I've ever made.
Okay, so beats per minutes to 40.
But we can just it yet, so that we're able to do that, let's go ahead and add two more rectangles.
And this might not seem like the easiest way to do it.
But I actually think this is a pretty logical way of doing it because in general, you're not adjusting beats per minute by one at a time.
If you want to, by all means make these plus and minus ones I'm going to make them plus and minus fives because most of the time you see speed beats per minute adjusted in increments of 10 or occasionally five.
It's really weird to see a song that's in like 137 beats per minute.
It's much more normal to have 120 to 40.
So I'm just going to do it in plus minus fives but you don't have to.
driving a motorcycle down the street scared.
Okay, BPM add rec so this will be the rectangle they'll let you do plus five and We'll say Pygame dot draw dot rect, we'll put on screen, we'll make it gray.
And this time, let's go a little bit to the right.
So that last rectangle we made start at 300.
And at 500, this one will just give it a padding of 10.
And then we'll put it at height minus 150.
So the height of the top of the rectangle, and we'll just make this 148 48, almost 5050, to where it'll almost these two rectangles will almost fill the full height.
But not quite, I just think everything looks a little better with some padding around it.
And then we'll say BPM, sub rect.
So this will be the button that lets us subtract five from your beats per minute, it will do Pygame dot rect, put it on the screen, make it gray.
Now this one, still at 510, we want it the same height, or we want it the same exposition, but then we'll just do height minus 100.
And now since they're 4848, we have a little bit of padding, which will be nice, as you'll see when we load it in.
And I really want to emphasize the style stuff, you can do whatever you want with yours.
So if you don't like the way Mine looks, or you think it would look better, in some other way, tweak it change how big fonts are, change your font, change your colors, do whatever you want, I'm just trying to give you the functionality.
Okay, so then what we'll do is we'll create some ad text.
And this will be kind of nice, because we can use it on the beats per minute buttons.
And I guess in theory, we'll want to do just plus minus ones for the beats.
So forget what I was about to say.
Okay, add text is medium font, dot render, because these are smaller buttons, so we can't afford to make them huge.
And we'll do plus five for add text, true and white.
And then sub text sub text Nice.
That's the thing, medium font dot render.
And then in string variable minus five, true and white.
And then let's do screen dot blit for add a text, and let's put that a little inside.
So 520, because the button starts at 510, and then height, minus 140.
So a little bit down.
So we're giving it kind of a bracket of 10 on the top and the left, and we'll see how that looks.
It'll do about the same thing for the sub text.
So 520 and then height minus 9090.
There we go.
All right, and we haven't had any functionality.
So nothing happens if you click it right now, but let's see if that looks good.
Okay, so next thing we're going to do is we're going to make, it's where when you click that button, it actually adjusts your BPM by plus or minus five.
And that is not hard to do.
So we'll come down into our mouse button up code where we check if the if the play pause button gets Wow, that was hard for me to get out.
If the play pause button gets pressed, and will do if add BPM, add rect dot collide point, collide point, event dot pause.
And so if that's the case, then we just want BPM plus equal five, and then we'll do an L if BPM sub rect dot collide point, event dot pause, be Pm minus equals five.
And actually, we can make our code slightly more optimized by making these all LFS because in theory, we know that these buttons are not in the same spot.
So we can save our code a little bit of time, by not bothering to check if you click these other buttons if you already click this button in this loop, because you're not going to be doing both.
And that's super simple.
That should be all we have to do.
So let's go ahead and check it out.
I'll go and put some sound in here.
bunch on lunch, and let's see if we can make it faster Yeah, it's given me anxiety.
Okay, but hopefully, if you're following along, that's really cool.
That should be like super encouraging.
You just made this happen.
You are a programming King.
Good work, keep it up.
Maybe I'm just talking myself, but I think you're enjoying it too.
Alright, so the next thing we have to do is we have to add beats and that is going to be a little bit trickier because we have to obviously update our clicked and update our total grid.
So we have a few lists that have to get updated if we change how many beats are in the song, but we can start basically with the BPM stuff that we just made.
So we'll say beats stuff.
So, you know, yes, there's a little more programming we have to do on the back end, but at least to get the rectangles drawn, it is not going to be too bad at all.
So we have beats rekt beats, txt, beats.
txt, beats txt to even because it really is, it's a second.
It's a second version of the BPM, something that you should have control over, we want them to be able to add and subtract.
So we'll say add text to sub text to add text to sub text to and we'll do one beat at a time.
Because technically, you could have any, you could have any time signature, you could do nine beats total, if you really want to.
So we'll say beats in loop.
And this time we are at we are currently our right limit, I guess, is 560.
Right? So would it make the most sense to start this at 600? Probably.
So we'll do 600.
And then everything else, I think is fine, this will be 608 670.
And then this one should probably now be 810 810 828 20.
And we haven't added anything for operational code yet.
So nothing happens when we click these buttons.
But that looks good.
Let's move the text to the right.
Because this is not as long so beats in loop can be like 618.
And this can be like six ad I think that will look good.
Yeah, that looks better.
All right, moving on.
The actual functionality that we need when we click these buttons is a little bit more complicated.
So let's take a look at what we need to do when we collide with the points.
Alright, so we'll come down to these to be BPM, add rect and subtract.
And we need to do an L F beats add rect collide point and LF beats.
And initially, we can kind of use the same code because we're we are going to take the beats variable that already existed, and we're going to add one and subtract one.
But that is not enough right there.
Because we have to, we have to add a full row, a full empty row to our grid.
If it was make sure I say this write a full empty row to our grid.
If we add a B, and we need to remove the last row in our grid if we subtract a B, so what we need to do is say for i in range length of clay clicked length have clicked There we go, we need to remove a weight, this is the plus one.
So I am going to steal this.
There we go.
And so this means we've just press beats minus one.
And what we need to do is we need to say for i in range length have clicked clicked at I so this is going through each row of our clicked list.
And we're going to clicked I dot pop, which is the python list function for removal.
And we're gonna pop the minus one which means the last character on the end, so there's this way you can address this is the index inside that list.
And if you do a negative, it's counting back from the end of your list.
So pop minus one, this is going to go through and remove the last item in our in our list for the click List.
And then for the beats plus one we go through and we do essentially the same thing do to do so actually, I was on the right track already.
Except instead of pop minus one it's actually kind of fun, it's append and it's still a minus one because minus one means not selected.
So this is now everything so I think this is going to make let's see Fingers crossed.
So we hit plus one and now we have nine on the screen how cool is that and the entire screen updates every time we add one so now we can go ahead and do 12 beats I'm gonna pause it while I set this up so bass snare bass bass snare, bass snare crash.
Yeah and this I mean you can play around with it already if you want but this can keep going you can make this thing 48 Right here.
You will notice it's a little bit tedious to fill in 48 beats but it's we set it up in a really smart way so that this is completely adjustable based on how many AP how many beats you want in your loop.
So I mean awesome job guys.
We are just cruising along here.
Let's add some more functionality.
Because this is going really well, let's add the ability to turn off a channel so that you can edit it without it affecting your live loop and turn it on and off just like that.
So to do that, we are going to come up and we are going to create some instrument rectangles.
So essentially, they are just let's go down here underneath the beat stuff.
And we'll say, instrument racks.
And I'm just doing this so that we can click on the channels.
And we'll say, instrument, racks, equals, and then a empty list.
And then for i in range instruments, and I'm trying to make it so that if you copy this code, and then later on, you want to add some more channels, I'm trying to make it as scalable to that automatically as possible.
So we'll make this little rect equal to pi Game dot rect dot rect.
And you'll notice what I'm doing now is I'm defining a rectangle, but I'm not drawing it on the screen because we don't need it on the screen.
And for this one, it's a little different, we're just defining a rectangle.
And so this one needs to tuples instead of a list of four characteristics.
It needs an x&y Starting position, and so x&y Starting position will always be zero, and then I times 100.
So just just as we go through the list, it's going down 100 at a time, but it's staying all the way on the left.
And then the width for all of these was 200.
And they're all 100 Hi.
And then we're going to do instrument racks, dot append.
And that rectangle, okay, so what we're doing is every loop we're coming through, and we're creating this list of rectangles for those buttons.
But we're doing that so that we can come down in our in our collision detection inside of our mouse button up clicking.
And we can check if any instrument rectangle was clicked super easily.
So to do that, we'll say L to L f, we will say for i in range, length of instrument rectangles, okay.
So this is going to check every instrument rectangle that we define.
And what we're going to say is if, right, if instrument rats, sorry, I tried to give my variable names, long descriptive names, so that as you guys are following along, it's pretty clear what everything is.
But these are maybe longer than you would want to use in an optimal project.
But so we're going to check if every rectangle in there was clicked, we'll say if instrument Rex dot collide point with event, dot position, then what we'll do now is we're going to create a new list, and I'll call it active list.
And we will set whatever instrument was clicked.
So whatever is that active list, I times equals minus one.
And so we're going to use the same kind of logic we had in our clicked list for our active list, but this is going to be a little simpler, because it's not really an array, it doesn't need to be a list of lists.
So we'll go down to clicked and read only if clicked, I will make another list called Active list, you could call it active channels, active instruments, whatever.
And in the beginning, I'm going to set them all equal to true because I actually think our default will be having all of your instruments on.
And it's just going to be one for underscore in range of instruments.
Okay, and this is just going to give us a list of six ones saying all the channels initially will be on.
But if you click on a channel, it'll turn off.
And where we'll update that is we'll go into our draw grid function.
And we'll pass in that active list.
So we'll say actives, doo doo, doo doo down here, and we'll give them the active list.
And now do do actives.
So you remember this colors, gray, white gray that I made before, I would like the text of each instrument to be the color of its active list position.
So essentially, if you click on it, then I want it to be a one meaning it's active, or a negative one, which is actually going to be great because remember, a negative one is the last item in a list.
So I just think that's a clever way to do now.
Hi Hat text is going to be colors zero.
Wait, wait a second.
Colors, no active actives.
00 Okay, so let me be super thorough to explain this item because now it's a little confusing, we're referencing an index item of a list in a list.
But actives zero is telling us whether or not we currently want high hat to be active, right? So is this is going to be a one or a negative one, depending on whether or not hi hat is on.
And so if it's a one, we want to be white, if it's a negative one, we want to be gray.
So now we just do this exact colors logic that we did here, for all six instruments, and we just make sure we update their index location.
And as soon as I do this, I will load it up and show you what we're doing.
So do 234, and five.
And again, if you need extra clarification on anything we do in this, just let me know about in the comments, I'll get back to you soon as I can.
So if I click high hat, you can see it turns gray, which is great.
If I click snare, it turns gray bass drum, I can sort of make these inactive.
But what does that mean for the actual code.
And so we need to come into our play notes function because it's going to impact it in here as well.
So what we need is if clicked i is equal to active beat.
And we need to check and active list at i is equal to positive one.
Okay, so this is all we have to do now.
Because when we check and see oh, it's time to play the hi hat, because in my beat that I've set up, it's a one.
Well, we checked and saw that actually hi hat is turned off.
So it is not time to play the hi hat.
And it'll work that way for all of them.
So that's all we have to do there.
But it's still going to look bright green on the screen.
And so it might be a little confusing why it's not playing, maybe you didn't notice the text was dark gray.
So let's also in the grid, I think I like this idea.
We'll go up to in here where we check the colors.
So if it's not selected, it should be that light gray, that basic gray already.
But then what we'll do is inside of this else statement, we'll check if actives at J now it's actually J is the beat for this loop.
So hopefully that's not confusing for you.
But maybe it is, this is checking what instrument so if our active instrument is positive, then the color should be green.
There we go.
There we go.
Okay, but if the actives, J actually, we can just do an else here.
So we checked to see if it was a one.
If not, then we'll want our color to be equal to dark gray, dark gray.
There we go.
So now let me explain what we just did.
But make sure that you're following along.
And hopefully I didn't confuse you too much.
So let's say you have a high hat playing every beat in your loop.
And then you want to add some bass.
But then you want to kind of see what sounds like without the hi hat.
Okay, you can turn just that channel off.
And you see the squares go dark gray.
But what's cool is that still gives you the ability to edit it.
So you could still be working on your beat.
And then turn it on.
So like let's say I want to add some crash and some clap.
I don't know what these are gonna sound like this could be wacky.
But now I could turn all this stuff back on at any time.
And then you get this whole kind of funky be actually it doesn't sound too bad.
And I'm gonna turn the bass on the floor toms off.
And we have individual channel control.
So that's really cool.
That's another cool feature that like a standard drum pad would be able to do for you.
So okay, we have play pause, we have beats per minute, we have beats in a loop, we have all of the ability to add beats, add speed, add a hi hat, or turn off individual channels, things like that we've looked at how to load in the music.
So I think we're getting to the point where we need to work with an external file to be able to load and save specific beats that we've created.
So we're going to do that next, but I need a quick water break.
Okay, so the next thing I want to do to our app here is I would like to add a Save Menu and a load menu.
And I'm going to put them on two different menus because I think that kind of helps separate out functionality, but you could probably put all this on one.
That's just up to you.
But let's get into it.
Okay, so let's start by just drawing the rectangles because from there we'll start Bill Hang out how this actually needs to work.
So let's come down to where we draw everything.
And we have so many rectangles and beats and instrument rectangles all getting drawn.
Next thing we'll do is save and load stuff.
And we can pretty much use the same rectangles that we've been using in the whole menu, because there's nothing wrong with them, they look just fine.
So we will say Save button equals, and that'll be Pygame dot draw rect Skrein.
And now we need to make sure we keep moving them to the right, so that'll be this one, we'll put at 900.
And we'll put height minus 150.
And actually, I think it'd look cool, maybe, if these were one over the other.
So height is 150.
And then 200, wide, and we'll only make it 48.
High, kind of like the plus and minus buttons, because we'll do save above load.
And we'll just see how that looks.
So zero, and five, and then we'll do load button just underneath it.
So my copy the same button equals Control V and then minus 100.
And everything else is the same.
Yeah, those buttons look pretty good.
Let's put text on them now.
So I'll grab actually, I think these maybe can be label font, I think that'll be all right.
So we'll say save text equals, and it'll be label font dot render should be pro at this by now.
And we'll just say save, beat.
And we'll make it true.
And we'll make it white.
Guys spell things, right, true and white.
And I will take this whole thing, save text.
And we'll do the same thing for load, load text, load beat, true Drew and wait.
And then we need to put them on the screen.
So screen dot blit.
Screen dot blit.
And this one, we want to save text.
And we would like to put it just a little inside the button.
So 920 and height minus 140.
And that should give us a nice, fairly square in the center button kind of thing.
And then we will do screened up but load text.
And then this can be 920 as well.
And then minus 90.
And let's see, again, we're not pressing those buttons yet.
But yeah, the text looks good.
You can play around with the spacing if you want.
They're on the buttons.
So what more do you want from you guys? Okay, save beat load beat.
And the reason I put them one over another is I want to add another button.
Once we're done with this, that's clear board.
So like let's say you filled in, like this whole board with squares, and you totally regret it and you just want to scrap it and start over, rather than closing the program and then opening it back up, we'll just do a clear board functionality.
So actually, that's going to be easier than the save and load.
So why don't we just do that, right now we'll do like clear board, because that's gonna be like three lines of code.
So clear board, we're going to add CLEAR button.
And it's going to be same button.
Actually, I'm just gonna kind of copy all these because it's just going to have text as well.
Pygame dot draw dot rect screen.
And then we'll want this 900 It's 200 wide.
So we'll want it at like 1150.
Does that make sense? 1150 and height.
And this one can be the full 100 high I would think and then this text will have it say clear board.
Okay, clear board.
And then we'll put it at 1160 and height minus 130.
Let's try that 1160 height minus 130.
And this will be clear text and clear text.
All right, so let's see if that looks.
I would like to move that down some height minus 120.
That'll look better.
Okay, let's do the clear board real quick, because clear is way easier than save and load.
Save and Load is going to be a lot of dealing with external files.
And I think just this is going to be a little faster.
So let's go ahead and check if the clear button collides with the point.
So we'll come down to our LFS because it fits nicely in here and we'll say LF CLEAR button dot collide point event dot pause.
So if you've hit the clear button, then actually what we're going to do is we're just going to set the clicked list equal to what it is in the very beginning.
So, you know, we check how many instruments and how many beats, and we just set them all equal to minus one.
Well, we can just come under our clear button and do the exact same thing.
And so that is really it.
All right, let's check that out real quick.
So we've got a whole bunch of high hats and some, there we go, just a random, terrible button, you're like, Oh, what have I done, clear the board, you're empty, you're free.
There you go.
Okay, so we have clear functionality.
Now, let's do the save and load.
And I want to do it, where save and load will actually kind of stop playing the music, and it will kind of make it to where you can't click the rest of these buttons.
So what I'm gonna do is I'm gonna create two new variables called Save Menu and load menu.
And we're going to use those kind of similar to playing to see like, if something is currently true, so up by be changed, I'm gonna say Save Menu, and it will be equal to false when the game starts.
And so we'll load menu, they'll both be equal to false right in the beginning.
But one thing we are going to do in the beginning as well, and you'll want to do this, you'll want to drop an empty text file into your Pygame project.
So if you need to make one in the outside world and drop it in, that's fine.
But if you have a decent IDE, you can do new file, and then just call it like, my beats or whatever dot txt.
I already have one called Saved beats dot txt, and to say like, Hey, we're going to be using this inside of this program, then you want to start early in your function and just do file equals open, and then save beats or whatever the name of your text file is dot txt, and then comma, and then since in the very beginning, we want to read the data.
And so let's say you close down the your session, then two days later, you come back and you want to do a new session, you want to read all of the information that's in there currently.
And we'll do it kind of like a CSV or comma separated values file, where each line in the file will be all the information we need for one beat.
So it's going to be how many beats are in it, how many BPM What name did we give it and then the clicked list of that guy.
So we'll do for line in file, the file that you have, and we'll make a list called Saved beats dot append.
And then that line, okay, and saved beats doesn't yet exist.
So right above file, let's just do save beats is an empty list to start.
Okay, and since right now, we don't have any saved beats, it's just going to be an empty variable until we do save some stuff later on.
But this is how you open up and store the data from a file initially already, so let's go ahead and use Save Menu and load menu.
Now if we come down to our buttons, and the first thing we're going to do is check to see if you've clicked on a button.
So if you click on save menu, or you click on Load menu, and one thing that we're going to add to all of the mouse button logic so far, is we're going to say if mouse button up and not save menu and not load menu because technically everything is going to be there.
Even after we load in a new screen that's going to be covering it up.
So we just want to make it to where you don't have to worry about clicking the buttons on the underneath after we've created a new menu.
So all of that's great.
And then kind of the counter to this is once we have save menu or load menu up, we need to make sure the buttons in there can be pressed and we'll do that by adding a new line that's going to be and so Pi game mouse button up and save menu or and and load menu and we'll do that a little bit later.
Okay, so let's get down to business and not save menu and that load menu and then we'll want some LFS in here checking if Save menu or load menu are clicked so LF Save Menu, save button, dot collide point with event dot position.
Then we want save menu to be equal to true and then we'll say L F load menu dot collide point To event dot pause, then we want load menu to be equal to true.
And we don't want to run this code just yet, because it'll disable all of our buttons.
And we won't be able to do anything but close it.
But this is going to make it to where our Save Menu and our load menu do get opened up.
And when we're loading in, I think, yeah, we'll just leave it like that for now.
So what I mean, when I say we need to kind of take this exact same code, but it we're going to need to do some different stuff with it is we're going to use this menu.
So we'll say l f.
Now because we don't want to run this if Save Menu and load menu or false, but we'll say L F event dot type Pygame mouse button up.
And we'll just say we're going to create an exit buttons.
So we'll say if exit button dot collide point, event dot position.
And we'll use an exit button on both the Save menu and the load menu just to get out of it.
So even before we actually set up the functionality of saving and loading, we just want to have the ability to enter a menu and then exit the menu.
And we'll just make sure that playing is equal to true, when you get out of the menu just on the off chance it pauses, it shouldn't, because we don't have it set up that way.
But just now we have it.
So we're not doing anything with Save menu or load menu yet, but we want to so let's come up to our other functions, where we draw stuff screened up fill boxes.
Yeah, and so we want to do before even the box is getting drawn.
So screen dot fill is the only thing that's happened yet.
And we'll say if Save Menu, then we'll do a function called Draw Save menu.
And then we'll say same thing, if load menu, then we'll say draw load menu.
And just so I don't forget, we want to make sure we get the exit button back from both of these.
Exit button equals draw load menu, draw Save Menu, okay.
And that's really what we have to do, we have to think about this in order of what's the bare minimum we have to do to get these menus going.
And then we can start adding the actual functionality to them.
Okay, so let's take a look at, it doesn't really matter which one we start with, they'll be sort of similar in format.
So we'll come down just below our draw grid.
And we'll do draw Save menu first.
So draw def.
Bow, I'm having some trouble typing, def draw Save Menu.
And we just have to make sure we return an exit button before anything else.
Let's just make sure we don't forget that.
And let's honestly, let's just put that on the screen first.
So we'll do exit button.
And let's not call it exit button.
Because we use that so many places.
Let's do exit btn, just to separate out, and we'll say exit btn is going to be equal to that Pygame dot draw dot rect.
And we'll put on the screen, we'll make it gray because all of our buttons are gray.
And for x position.
Let's put it at very far over to the right, so with minus 200.
Let's do with minus 200 and height minus 100.
And then for wet floods make one excuse me 180.
So it doesn't quite touch the right side and 90 so it doesn't quite touch the bottom.
And then we'll make it a solid rectangle with rounded rec tangle edges of five just like we always do.
And let's make some exit text here that's going to say close menu in label font.
So label font dot render.
And it'll just say close and do to do true and white.
Let's do that.
And then screen dot blit screen dot that exit text, and we want it what do we want for the coordinates for this guy? We'll put it with minus 160.
So we want inside that button with minus 160 and height minus one oh eight minus 70, they'll do a little bit of cushion there.
And let's see, I'm basically going to copy this entire thing for draw a load menu, just so initially draw load menu.
So initially, we have the ability to just test out opening up those two windows.
But we do actually, you'll see, this is gonna be a little weird.
If we don't do another step, so let's say we're saving the beat.
Okay, we're in some menu now.
But we haven't done anything that's going to make it feel like a menu.
So boo pool has no object, load menu dot collide point oops, this, what did I do? Exit button.
Oh, I did load menu instead of load button.
There you go.
So one thing I want to say we want to draw a rectangle that's basically the full screen.
So Pygame dot draw dot rect, put it on the screen, make it black.
And make it the size of the entire rectangle.
So start at 00 Make it the full width and height, and no rounding no edges, we want to be solid, and make that the first thing you draw on your menu and do it for both.
So what you'll see now if I hit Save beat, well, you'll see nothing because I did something wrong.
Let's take a look.
Oh, so it's not working.
Because I put these way too early.
You want these menus to kind of be the last thing that you draw.
So after everything else is getting drawn.
So after the clear button after everything, we want the drawing of these menus if the menus are selected.
And the reason for that is this code is drawing things in this specific order.
So the last thing it's doing is right at the bottom, checking if you have a menu active or not.
So we have this ability now to go into the load menu and the Save menu just like that.
And to kind of illustrate, what else we could do is we could say while we're in these menus, we can pause this stuff.
So the buttons aren't doing anything but that music is still playing.
And if that bothers you, then super easy thing to do, would just be set playing equal to false.
While the menus are active, I actually think it might make sense to have it still active wall while we're in there.
Because if you're saving a beat, maybe you want to be hearing it to think of what a good name for it would be.
But okay, this is good.
The important thing was that we were getting those menus to work because now those menus are blank slates that we can open up and do our work in.
So we can kind of stop messing with the main loop, which is getting pretty gummed up.
So we'll start by just working in these menus.
And so to start with the draw saved menu do to do, let's do draw, save, because it's a little bit simpler drawing the loading menu, we have to kind of sort through everything that's been saved.
And that can take a little while.
So let's start here, we have the full rectangle.
Let's call this menu text.
And we'll just kind of tell them what they're doing on the screen.
So we'll say render and we'll say Save menu.
Enter a name for current beat, okay.
And we'll make it true as always white as always, screen dot blit.
As always, and let's put the menu text menu text.
And let's pick a good spot for about 440.
And let's see what that looks like.
So save menu, enter names current beat.
Looks pretty good.
I'm happy with that.
So that's cool, but we haven't, we haven't really done anything yet.
We've just got that going on.
So next, let's put some, let's put a button down before we worry too much about the typing space.
Let's put a save button on the screen.
So we'll call it saving button because there's already a save button.
So that's maybe a little confusing, but that's what we're doing.
Okay, pi game, pi Game dot draw dot rect.
And we're putting it on the screen.
And we're going to make it gray because that's what we do with buttons.
And we'll put it sort of in.
We're making it fray.
We'll put it pretty much in the middle of screen.
So we'll do with that Yeah, width divided by two floor divided by two, and then we'll do minus 200.
So this will be a real wide one, we'll put it height times 0.75.
So we'll put it three fourths of the way down the screen.
But we'll make it 400 wide and 100 tall.
Because it's a big button, it's kind of the whole purpose of being on the screen.
So we'll make it a bigger button.
Saving button, and then we'll do saving, oops, gaming, saving text saving txt.
And that will be label font dot render, label font dot render.
And this will have the text be save beat.
And true and white.
And screened blit saving text.
And we want to put it at about the same spot.
So around width divided by two, maybe minus 50.
This time, because let's say it's 100 wide, maybe, I'm guessing, and that could be a good spot for it.
And then we'll do height times 0.75.
And then we'll do plus 1020 30, we'll put it in the middle of button 30.
And that should give us a big ol button that says save on the saving screen.
Save be Yeah, we want to move that to the left a little bit.
Okay, but we've got the beat the button on there, which is important.
And let's move it minus 70.
I don't know I'm winging it here.
See if beat.
That's pretty good.
Okay, so we've got to save beat.
And now, one thing, we're already returning the exit button.
But we also want to return the saving button.
Because we are going to check if we collide with it and the outside world.
So go down to where you are drawing your save menu.
And we'll do exit button and saving button.
And we'll use that later to check whether or not we're saving the beat already.
And now we'll want to pass in a few things into this actually, we're going to want to check the current beat name, because we're going to be typing in to save a name.
And then we're going to want to check whether or not we're actively typing.
So yeah, it's not happy, because those are not yet variables.
But we'll come up here.
And we're going to make these new variables, we're going to make beat name.
And I'll just be an empty string initially.
And we'll make a new variable typing, which initially will be false.
And then if we come up into our draw Save Menu, then you'll see we now are passing in beat name.
And we're passing in the typing variable.
And so to do this, we're going to make a new like entry box in the middle of the screen.
And so we'll call it doesn't really matter where we put it, we'll call it the entry rectangle.
So entry rect.
And that'll be equal to pi Game dot draw dot rect.
And we'll put it on the screen and we'll make it dark gray.
And we will, let's just make it regular Gray, because we use dark gray to signify whether or not it's been clicked.
Okay, so screen gray.
And then let's just put it at 400 200 600 200.
All right, so it'll be the middle 600 pixels of the screen 200.
We'll get down from the top by a little bit.
And we'll make this sucker five by five.
So there's just been a big empty rectangle.
And then we're going to have the entry text, which is going to be basically telling us what we've currently typed in.
So label font dot render, F string of beat name.
And there we go true, and white, and we're going to want to blit that screen, dot blit the entry text and we're going to want to put it right inside that variable, that rectangle, okay.
And we need to return the entry rectangle as well because we need to be able to click on it and determine whether or not we're actively typing or not.
And I believe that's all we'll need.
Okay, so now let's go back down to where we call that and make sure that we're passing the entry rectangle back.
So unresolved, draw Save Menu did accidentally change the name of the draw Save Menu, beat name and typing, I'm sure I put Another, oh yeah, I put a semicolon in there, such as silly goose, okay.
And tree rectangle.
All right, so let's do something with these buttons, I'll show you what it looks like now you should be running it on your own as well.
And you see, we've got this nice rectangle in the middle where while we're typing a beat name, it'll load in.
So let's go ahead and close.
And let's do something with all these buttons that we've got.
So now we have to go down and check what to do if all these different things get clicked.
Okay, so we are in this section now, this L F, type pi game mouse button up, where we have the exit buttons.
Obviously, to kind of reset everything, and we'll clear out the beat name.
So if you were halfway through typing a beat name, and then you close the menu, we'll set it equal to empty.
And if you were typing, we'll set that back equal to false because now you're obviously not typing.
And so let's start taking a look at the things that we just defined and in the in the menu and what we want them to do.
So if you click the entry rectangle, then what are ya, if you click on that rectangle, then what we want to do is basically change what state of typing you have.
So if entry rect collide, point event dot Pause, pause, then we will say if typing, then typing equals false.
And then we'll say L if not typing.
So again, this is where if you just did an else, you'd get this tricky little thing where it comes in and says, Oh, if typing, typing equals false, else, but then the else is checking if not typing, and so you'll just get this kind of sticky situation.
So do an lf not typing.
Set, typing equal to true.
And we're just going to use if typing to handle a new type of event.
So we'll come down into the level of this like l f.
So this L F, and we'll say if event dot type, equals and now we'll use a new type, which is Pygame dot text input.
So that's you've hit a key that has a text value, and the typing variable is true.
And so this is how we'll handle not modifying the beat name if you're not actively typing.
And then we'll say plus equals event dot text, because when you hit a text key, a P or an underscore and apostrophe, or an M, the value of the actual key that you hit as it appears in a string is event dot txt.
Okay, and then we'll say if event dot type equals pi Game dot key down, and we'll check if so key down is another type of event.
And we're using this to check if this specific key that was pressed if event dot key is equal to pi Game dot k underscore backspace, so we want to check if the backspace key was pressed, and the length of beat name is greater than zero.
And this is an important step because if the beat name is already empty, we don't want to try to remove text from the variable that's keeping track of the beat name, it's already zero characters.
But what we have to do here, because there's not really an easy way to just pop a character out of a string, you have to redefine it.
And so what we'll do is we'll say beat name now is equal to the current beat name.
And we use this range of characters.
And so leaving, leaving there as no character before, this colon means start from the very beginning.
And then a minus one means go to the character that is right before the end of the character.
So this is basically just a way of grabbing the entire string up to the most recent character.
And so just with these two, we have added functionality that's going to let us remove and actually we want another and typing condition there.
So now the entry rectangle should determine whether or not we are actively typing or not.
And then the the text input and key down characters here should change whether or not we're able to do anything, so we haven't handled the actual Save button yet.
We will we will do that next.
But now let's go ahead and see how our menu works.
I'll click in here and now I should be able to type Pete, Backspace, Backspace, Backspace.
I'm going to type Pete is cool.
Now if I click this rectangle again, And I keep typing.
Yep, it's not doing anything, which is good.
That's what I want.
But we haven't visually shown that anyway.
So let's go back into the Save Menu, do Save menu.
And let's add like a dark grey insert rectangle that says when it's time to type.
So or maybe a light gray would make more sense.
But I'm going to do with the dark gray because it's my tutorial.
And so what I'll do is, I'll say before the entry wrecked, so where was that entry wrecked here? Yep, Ctrl C, I will say if typing.
And then I'm gonna put this rectangle in here, and it doesn't need a name, because I'm just using it to signify whether or not we're typing, and I'll say dark gray.
And I will just make it solid, in the same footprint, and that's okay, because we're drawing it first.
So your edge will still show up.
And that should now be a good way to signify so save beat.
There we go.
Pete, is cool, okay.
And if I click off of it, okay, well, now I'm not typing anymore.
And now I am.
And I can do backspace, and whatever.
And if I close it exits, and that's great.
So let's go ahead and handle the Save button.
And I kind of been putting it off because working with external files and saving data to a text file is just a few extra steps.
And, and we have to kind of choose what data to store and in the right format.
And it's a it's a process.
So let's get into it.
Because it's very important to the functionality of this, obviously, being able to save your favorite beats and come back and use them later is a huge value add to this kind of thing.
So we'll come down here where we have our entry rectangle, and we'll add a new one.
And we can really do these as LFS as well.
And so we'll say l f.
Saving button, be very careful because now we have a save button and a saving button.
And we'll say collide point with event dot pause.
And if so then what we want to do is kind of again, file equals open, and our saved beats dot txt file.
But this time, remember, in the very beginning, we read from it to store data into that variable.
Now we're going to do a W and that means we're going to write to it.
And what we're going to do is we're going to take that saved beats, save beats list that we made in the very beginning.
And we're going to append some data to it.
And if you remember I know is a little while ago, we said what we're going to be adding, we always want to start this with a new line.
Because if you don't, then anytime you save, then you could potentially be saving onto the same file.
And then the way we're parsing data with like per line, storing it as one entry in our list would get messed up.
So we'll do it this way.
We'll do name, colon, and then space.
And then we'll do string brackets, beat name.
So this is what you entered will be underscore name, okay.
And then we'll do comma, and then we'll do beats colon space, curly brackets, beats, and do pay attention to the format that you save it with.
Because later, we're going to kind of have to reverse engineer this for our loading menu.
So we're saving everything we would need.
We're saving everything we would need to be able to recall this later, we're saving the clicked list, we're saving how many beats and beats per minute, and then a name that we gave it to to be able to save it.
And so we're going to add this as one item to our saved beats list, which means it's going to be the format of a saved beat.
And then what we'll do is we'll say for i in range, length of saved beats, there we go.
We want to do file dot write a string of saved beats.
And this is what you have to do because to write to a txt file, it has to be a string.
So you have to make a string conversion of each entry of your saved beats list.
And then to get it to save outside of that for loop, we're going to do file dot close.
And that'll close up the text file, file the new data, and then we will go ahead and close the menu.
So now Save Menu equals false, capital F false, because if you've just saved your beat, there's really no reason to stay in there.
And then we'll set typing equal to false because that's kind of our default and we'll clear out the beat name variable.
So this is kind of saying you've accomplished what you're here to do.
And now even though we don't have a way of loading it back in you can see we have an M Do you save beats txt file right now let's go ahead and make one.
So let's make a beat.
I'll just make it the kind of like generic rock beat, I've been doing.
Sweet, I made a save beat ama call it generic rock beat.
And I'm gonna hit Save beet.
And let's see.
Okay, it's good sign, it didn't close anything.
Let's go ahead now and look at our text file, so you can get an idea for how we're saving it.
Okay, this is pretty cool.
Its name generic rock beat, beats eight BPM, 240.
And then selected and this is the list, you can tell it's got all of the hi hat.
So that's what this first one is.
And they're all on, which is why they're all ones.
And then this is the snare I believe.
And you can see it's just the threes.
So like, 12341234 for the snare, the kick drum is one and then one, one.
So you can tell this is a list of everything we would need to do to recreate that beat.
So once we've saved it, we could clear it out, we could close it and move on with our lives.
And, and that's really cool.
But we have no way of loading it in yet.
So that brings us to the load menu.
And I have been putting this off because it is probably the trickiest one, we have to take all of that information, we stuffed in a text file, and we have to reverse engineer it out of a text file.
So let's get started me complaining about it isn't going to make it go any faster.
So let's go into the draw load menu function.
Take a sip of water here.
Okay, so we have the back rectangle, and we have the exit button, which is a good way to start.
I'm going to kind of poach the menu text from up here and the saving text and kind of steal those because we're going to just reuse them for a menu text, which now will say load menu and select a bit to load in, we'll just say load, that's fine.
They know what they're doing.
And then instead of saving button, we will say loading button.
And instead of saving text loading text, and that will say load beat, and that will say loading text, but the positions are probably good.
And then obviously, in addition to exit button and everything, we are going to need to do the loading button as well.
And I think we will want to also return a delete button probably because maybe you've put too many in here now.
So let's just also make a delete BTN.
That'll be good.
And so we have a loading button.
Let's go ahead and add loading text.
Let's go ahead and make a delete button, delete BTN.
And where should we put this Delete button Pygame dot draw dot rect rect and screen and gray you know how it be.
And let's put this one on the screen roughly.
So we'll do width divided by two to get the middle point.
And we'll do minus 400.
So kind of scoot ship left from there with minus two minus 400 That'll be the starting position.
We'll put it a little bit lower.
So height times what should we do point nine.
I don't know get a little delirious is a long tutorial.
Okay, we'll make it solid.
We'll make it round rectangle.
And we will just see where that is how that looks and kind of go from there.
I don't know why I would put this at point nine it should be at the same height as the load button.
But let's see.
So if this is starting at with minus 200 and this one starts at minus 400.
That's going to touch our loading button.
Let's try making this 500 I don't know I'm playing around now I'm in uncharted waters.
Alright, so we need to add some text we need to do delete text and put that on our delete button.
And that'll be label font dot render.
And this time we will do delete beat for the text.
Okay, and then it should be white.
And first we need to do true for the anti alias white.
Come on Pete you knows and then screen dot blitt and then delete text.
Okay and And for location on this, we just wanted to kind of steal the x&y starting position from up here CTRL C to the text and scooch it a little bit inside.
So let's see with now minus 500 instead of 500.
Let's do like 485 and then height times oh, point seven five my friend.
And then plus 10.
Let's, let's just see what we've done.
I think this is hideous, but let's do the load menu.
Load be honest, not the worst thing in the world is it? Okay? That looks alright, let's go ahead and scoot delete beat down a little bit.
What did we do for the other one plus 30.
We'll do plus 30 again.
Okay, and now we need to if exit button tuple has no attribute do collide point well, who's a tuple? Here? Exit button Pygame dot draw dot rect.
I don't fully understand why I got that air.
So tuple object has no attribute collide point I understand what that means.
But exit button is right here.
Draw load menu, exit button loading button, delete button.
Oh, maybe it's because we haven't told the loading button function.
It's getting a few things yet.
So hang on, we're returning exit button loading button, delete button, come down to where you call those menus.
And it's exit loading button and delete button.
And now the Close button should work unless I'm crazy.
And I am not.
Well, I might be but let's move on.
Okay, so back in the loading menu, we need to kind of set up a area that is going to be where we display the info from our loaded beats.
So load menu, select a beat to load we say that we put the text on the screen.
But we do not show currently, like the area where the beats might be.
So let's draw I think like kind of a holding pen, like a rec outer rectangle where all the data is going to be displayed.
So let's just do Pygame dot draw dot rect.
Let me think what the right way to do this would be? Yeah, let's draw a holding pen, if you will.
And let's say pi Game dot draw dot rect.
And let's put it on the screen.
And let's make it gray.
And let's give it 190 100 Plus, which let's start at 190 200.
Let's just see how that looks.
And let's make it I don't know, 1000 high and 600 wide.
I don't know I'm kind of conflicted here.
Because I want this to be I think like a outline.
But I don't know if it makes more sense to have it like as a solid rectangle for displaying the loaded beats.
So whatever I did that's hideous, let's fix this.
Okay, let's fix this rectangle, I think 190 90 We can make it 1000 height will be fine.
600 should be fine.
Five and five is probably okay, I think what we'll want to do load beat I think what we're gonna do is just move load and delete lowered down because I do like the idea of being able to show quite a few different beats.
So maybe instead of point seven, five on these, we do try like point nine or close to it.
Let's scoot these down and do like point.
I don't know, eight, seven.
Let's try that point eight 7.8 7.87 plus 30.
Let's take a look at that load beat.
There we go.
That's not bad, actually.
Kind of that entry rectangle.
And so let's go ahead and call that something.
Let's call that.
I don't know.
We'll call it loaded.
And I think we want to return that too.
Because if you clicked in there somewhere, you'd probably be selecting a beat.
So let's come down to our function where we grab stuff back delete button, and we'll say load rectangle down there.
Or loaded it doesn't really matter.
All right, and And let's see about actually parsing data in this draw load menu.
So we have to kind of check on what index has been selected.
So first, you know, we should do we have a text file with one saved beat.
Let's go and make a second one.
Okay, so let's just make this stupid.
It's not the worst, not the worst thing in the world.
But I'll just call this Tom and clap.
Save the beat.
And let's go ahead and close that and look at our text file.
So now you see we've got these two.
And let's say we have the load menu.
And we want to parse through the data of those two and show them on the screen, we want to show how many beats they have.
We want to show their name, and everything.
So what we need to do is we need to start checking on, like, how do we get the specific stuff inside of those.
And so let's just dive into it.
There's no easy way of doing this.
So here's what we do, we start and we say for beat, in range, length of saved beats.
So remember, save beats is a list, where each item in the list is a long string that has one of those saved beats in it.
So for beat in range length of save beats, and let's just set up our rectangle, the display 10.
So if b is less than 10, meaning we'll start at zero.
Okay, beat clicked, is going to be equal to an empty list.
And we just kind of have to set up some stuff to parse through this, it's a really long string.
So row text is going to be equal to medium font dot render, and we're just going to show what row this is.
So it'll be F, and then that's a format string, and there'll be bt plus one, because it's going to start at zero.
But again, I don't really think we should say anything is the zero with beat, it'll be the first beat.
And we'll say true and white.
And we'll put that on the screen.
So screen dot blit.
And we'll give it the row text.
And we'll put it at 200 100 plus the beat 200 100 plus the beat times 50.
So that's how we'll make this work for every for 10.
Because the rectangles like 600, high.
Alright, so that should be all we have to do to put the row text on there.
But we have to start getting some indexes.
So this is where if you're familiar with string manipulation, in Python, you'll be a little bit ahead of the curve, because a lot of what you're about to see might not make a ton of sense, unless you're familiar with strings.
So we need to figure out where to start the name.
And so we'll say saved beats.
So that is the list of all the beats that we've saved, and then beat so we're calling our specific string.
And then we need to find the index value.
So this is where in that string, we first see this specific substring.
So the index of name colon space, and you'll see why I was so particular when we set up that write that right instruction to the list, because we have to replicate that in reverse to tear it apart.
Okay, and then because there are six characters in this string, and a m, e, colon and space, we're going to add a six right there.
And then the name index end, doo doo doo doo, and is going to be equal to saved beats at beat dot index.
And then it's going to be so this now is going to be where the next thing in our string is added in.
And so if you think about it, I'll actually pull up the text file here.
Name ends when we get to colon space beats.
So we kind of have to do this thing where we check where each piece of it starts and stops by doing this.
So beats just like that is going to be where we want to end it.
And then name text.
The actual text for each of these is going to be equal to and we'll make this medium font so that we can put it on screen dot render.
And then the text for it is going to be saved beats from apt beat so that tells you which item to use.
And then we need to do what's going to be from name index start and then colon name index end.
And so this might seem a little confusing, but we just what we just did is say okay, take the list of all the safe beats, choose it for the specific one we're looking at and Then from where this name text stops.
So basically, the next character, after this name, colon space appears all the way up until this colon space beats appears.
That is the actual text that is the saved name for this beat.
And then we want it to be true, and then White, and then we're putting it on the screen.
So screen dot blit.
And it's going to be the name text.
And it's going to be comma, and then 240.
And then 100 plus bT times 50.
That's not the times there we go.
Beat times 50.
And so this is just where we're putting the Rotex as well.
And let's go ahead and just start there.
Because I think if you're familiar with how this works, when we go to the load menu, you can see we have generic crack, beat, Tom and clap.
And those are the first and second names.
That's really great.
So that's awesome.
What we have to do now is we have to figure out how to parse the rest of the data because that is just one of the items.
And that's great for showing them on the screen.
But we also need to figure out how to get the beats per minute and the selected list out of there.
So this is going to be a little tricky.
Bear with me.
And again, if you get lost in specifics, be sure to slow the video down, rewatch the parts that confuse you and feel free to ask your questions in the comments below.
All right, so now what we're going to do is we're going to say if zero is less than or equal to index, and we're gonna get to this index variable we're about to make in just a second.
So if it's greater than zero and less than the length of saved beats, I'm typing all over the place, Shift Tab, get out of here, there we go.
And less than the length of our saved beats file, so this means that you currently have a beat selected, we're going to use index as a way of selecting a specific beat.
So this, I'm going to put it up here, so we don't forget to pass it in.
But we are going to select by clicking on one of those beat names, we're going to select which one we want to load in.
And that's going to be the index variable.
And then based on what's been selected, we're going to need to do some additional work.
So we're going to need to figure out where the index and for the beats is.
And that's going to be equal to saved beats at our specific beat.
So that's why we still want it to be do wait a second, let's save beats.
And we want to add a second condition here, and B is equal to index.
So that's why we're putting this inside of our for loops still, because this will check and see if while we're getting the names for each beat, this will check and see if we've also actively selected a beat.
And so and b is equal to index.
All right, then what we'll do is we'll say at that dot index, so just like before, and now the next one starts at colon space, make sure your string in a string variable colon space BPM, because this is where the beats per minute variable starts.
And so that makes the loaded beats, loaded beats, which is a new variable equal to integer of saved beats dot beat, try and be very careful here because we have to do this kind of double indexing thing again, so it's not safe beats that be it save beats at beat.
And then we have to do from name index end plus eight to beat index.
And so the reason it starts at name index end is because or name index n plus eight characters is because this is going to start with the colon.
And it's going to end eight characters later, which is when the actual beats value starts.
And that's why we put an iron T in here to convert it to a number.
So what it's doing is we're indexing from this character to this character, and we're turning into a number so even though it looks like eight as a number, this is actually inside of a string.
So it's just another string character until we do that i n t.
But now we're getting back the loaded beats, which is great.
And we have to do basically the exact same thing for the BPM so the BPM index end BPM, do index end, which has a new variable as well, is going to be equal to saved beats at beat.
And then it's going to be dot index.
And this one is going to be now when colon space selected, I didn't put it in quotes again.
Here we go.
When that appears, that's going to be the index that's going to say, Okay, this is the end of the BPM section selected, and that's going to make the loaded be PMS equal to pretty much the same thing as this loaded beats just with different index value.
So I'll grab that.
So this one is going to go from the not from the name index, and but from the beats index and and it's not going to be plus eight, it's going to be plus six.
I think I typed in eight again, and then this one is going to go until BPM index and beats index and interest, dang, oh, it's just beat index.
And there we go.
Okay, and so now we have the BPM, the beats and the name of it.
And what we don't have is just the trickiest part, which is going to be the selected list.
So we have to now loaded clicks, right, because we call it clicked in the outside world.
So loaded clicks, and I'm gonna differentiate it at loaded clicks as a string is going to be equal to saved beats, at beat.
And then we already actually have all the info we need for the rest of this one, it's going to be BPM index, and, but then this one is going to be plus 14, okay, and I'm about to explain why it's plus 14.
And it's going to go essentially to the end minus three characters.
And the reason for that is we need to do what's called splitting the strings out.
So if you say, this is where it started, so 1-234-567-8910 1112 1314 characters before we get to the first one, or minus one in our list, and then if you go to the very end, we have a space and then to end brackets at the very end, which is why it goes to minus three, that's gonna give us a string of all of our values.
Now we have to split that string into a list.
And to do that, we're going to use the built in Split function, but we have to tell them what to separate each list item on.
So we're going to split it, we go down to loaded, clicks, and we're going to call this now a row rows, because we have to split this twice, right, it's currently just one long string, we need to split it into a list of strings, and then we have to split each string into actual ones and negative ones.
So to do that, we create this intermediate list, which will be loaded clicks rows, and set equal to list.
And then inside of this, we do loaded, clicks string.
And then dot split is the built in function to split a long string into a list.
And it's going to be open bracket like that, and then comma, and then space, and then close bracket or backwards, close bracket, comma, space open bracket.
And the reason for this is again, if we look at the text file, what splits up in between each entry, each item in that selected list is a closed bracket and then a comma, and then a space and then open bracket.
And so that's what's going to split each item into its own list item in here.
Okay, so now, we get to do some more complicated stuff.
So bear with me.
And once we're through this, maybe really take a look at what each line is doing and think about what it's doing.
And really trying to make sense of it and then ask me if you still have questions after that.
But so for row in range, length of the loaded clicks rows list that we just made.
So we're setting up a for loop to go through there.
And we're going to say, if loaded.
Clicks do to do here we go.
If loaded clicks row, item.
So item is just checking.
We don't want this to be row we want this to be item.
I'm getting ahead of myself that we do want that to be row and we want to say loaded.
Clicks row Okay, is equal to, and I'm just going to create another intermediate variable just to get my head straight, because there's a lot of words going on.
So we'll say load clicks row is equal to loaded, clicks, rows plural at that specific row.
And then what we're going to do is we're going to split that row item split out.
And we're going to do it based on a comma, and then a space.
And the reason I add the space is because when you do a split, it's going to give each thing in between those its own item in the list, but it's going to get rid of this text that was in the string.
So we do it this way.
And then that's going to split it up and make a new list and that we're going to store that and loaded clicks row.
And then what we're going to do is go through and say for item, because they're not yet integers in range, and it'll be the length of the loaded clicks row that we just made.
And what we're going to do is we're going to check if loaded clicks row singular, at item, is equal to, and we'll check if it's equal to the string of one, or the string of negative one.
And the reason we're doing this is once this has been sorted once, we don't want to run it again.
So we'll say or if loaded clicks item is equal to negative one, because in theory, those are the only two things the items should ever be equal to.
And we don't need another if we just need an or.
So if it's equal to a string value of one or a string value of minus one, then what we do is we say that loaded clicks row item is equal to the integer value of loaded clicks row, at item.
And the reason we're doing this, if check is because once it's become an integer, this won't execute anymore.
So we don't have to execute this anymore, because everything is already an integer.
So that's why we do that.
And then we come out of the if and we say that we want to track what beat was, what what loaded in beat is, let me say this correctly, we want to make a list of the clicked values of what was loaded in.
So if we have this loaded, collect list that basically reflects the outside clicked world, then we want to make sure that we are appending at the right time.
So we'll come back up here to where we did this beat clicked list.
And we will append each list in here.
So we'll say let me make sure I got my indentation, right beat clicked dot append.
And we're going to add loaded clicks row, each time we do another row.
And then we'll say loaded click is equal to beat clicked, there we go.
And we'll want to as well as the loaded rectangle, we'll want to return the loaded clicked.
But we actually we need to return the loaded clicked, and we need to return the beats and the BPM.
So let's make another variable out here.
And let's call it loaded info.
And let's make it a list.
And so it'll have loaded beats in it.
It'll have loaded BPM in it, and it'll have loaded click in it.
Alright, but what we need to do, because right now there's a reasonable scenario where nothing has been selected yet.
And so these might not exist, because right now the only place we define them is if something's been selected, if we've set that index value, so what we want to do in the very beginning, is just initialize them like you would in the beginning of your program, but we'll do it inside the function.
So loaded clicked equals zero, loaded beats equals zero.
Load collect is an empty list, not zero, but you get the idea.
And loaded BPM is equal to zero.
Okay, so we need to do those three things.
And then we pass it all back in loaded info.
And so we'll pass that back instead.
So this was, I know, one of the more complicated things we've done manipulating strings like this is a little bit tricky, but we actually did some really advanced stuff here.
So if you're a beginner, you should congratulate yourself if you just managed to follow along and understand most of what we just did, because that's some pretty tricky string work.
Now, we get to kind of go down to the event handling and actually set up what we want each of these things to do.
So we come down here to the area that's outside of checking that it's not the Save Menu and load menu.
So it's the second part.
And we will come on down, doo doo doo doo if saving button client point length file.
Okay, so mouse button is up entry rectangle.
What we want to do now is we want to say do L F, and what do we say loaded rectangle.
So if loaded rectangle was clicked, then we want the index to be equal to, and we're going to use that event position at one, which is the y position, minus 100.
And then we are going to floor divide that by 50.
And this will give us a value one through 10 Telling us like where on the wire on the y axis we just clicked.
And we'll use that index for what the active beat should be.
So let's come back up and loaded menu and use that index to draw something that's going to indicate the actively selected beat.
Okay, so back in our loaded menu, we're passing the index in, let me make sure we're actually passing it in though.
Load menu drop down menu, here we go.
We want to make sure we pass that in.
And actually we don't, we don't initialize it in the beginning, do we so let's call it up here, we'll just say, index is initially equal to 100.
That way, it's not selected.
Okay, and draw load menu will say, Okay, if load menus is there, but we want to use the index to draw a rectangle on the screen, if it's in our range, so underneath load rectangle, I will say if the index if zero is less than or equal to the index, and it's less than the length of our saved beats list, so this is checking that we have one is less than the length of our list, then we will Pygame dot draw dot rect the screen, we will make it let's do a light gray.
So this will be the last gray I add, I swear.
And we'll make it 190.
And then we'll have it start at 100 Plus index times 50.
And we will have it 1000 wide and 50 tall.
So light gray.
Let's go ahead and define that up top.
And this again, it's moved in the opposite direction of our basic gray.
So light gray, and this will be like oh, like a 171 7170 Okay, and now I'm hoping when we do the load menu, load beat broke something too many values to unpack expected four, because I don't think I told it to expect loaded info coming back yet.
So let's see.
Law load menu loaded info, and load rectangle loaded info.
There we go.
Alright, so now let's open up loaded beat.
Generic rock beat.
Oh, string has no.
Yeah, sure did mean index I sure did.
So let's go check that out.
And which one did I put index for? index, index index.
There we go.
Alrighty, let's try that again.
Load beat, hey, we got a light gray rectangle.
If I click the top one, if I click second one, if I click third one goes away great, because there's no beat there.
And I click those.
But we are not able to delete things yet.
And we're not able to load things in yet.
So let's keep working on the buttons.
All right, back to our event handling down here.
And there are maybe ways I could have set this up differently.
But I kind of did them as we got to each event.
So let's come down here and say, All right, we have all these LFS LFS loaded rectangle.
Let's do l if delete button dot collide point with event dot position.
And then if we deleted something then what we want to do is actually not too bad.
It's if index.
So pretty much that same thing.
If index is between zero.
So index needs to be greater than or equal to zero.
And index needs to be less than the length of saved beats.
And I can say less than because the length of save beats is always going to be one greater than the largest index value of it.
So if there are three values in there, their indexes are 01, and two.
So what we'll do is we will just save beats dot pop, whatever was at the index, and that'll let us delete an entry.
That one's pretty easy.
We'll highlight the functionality of a few of these at the same time.
Once we get them working, Okay, so next, let's do the loading button because that one's kind of tricky.
And we will do LF loading button dot collide, point, event dot pause, that part's easy.
The next part is familiar.
If zero less than or equals to index less than length of saved beats.
Then we're going to set a few of our variables equal to the information that we pull in.
So beats is going to be equal to the loaded info that we pass back, which I believe we just called loaded info.
At zero, so the first thing was beats, loaded info zero.
And then the second thing was bpm.
And so that'll be loaded info at one.
And then the third was clicked, which will be loaded info at two.
And we will set the index back equal to 100.
So that's like an irrelevant number.
And then we will set load menu equal to false just like we did when the save button was pressed, because your work is kind of done now.
And we will, that should be all we have to do, I believe.
So let's go ahead and check it out.
Now, if we have got all of the functionality on that load button, I think the Close button was working I think we're able to click in there.
So right now looking at our screen, we have nothing going on.
There's nothing loaded in if I load that generic rock beat in well, I hit Load beaten nothing happened.
It did close load beat.
Let's try Tom and clap.
Okay, close I can feel it but no cigar.
So what's going on? Okay, I think the reason the loading button is not working is we need we just did LF loaded rectangle earlier, it needs to be LF loaded rectangle dot collide point where with event dot position.
So I'm really amazed the indexing and highlighting of the rectangles was working without this.
But that should let us load it in.
So let's go ahead and check load beat generic rock beat load beat.
There we go.
And that's really sweet.
Now let's try clearing the board.
That's also awesome.
Let's see if deleting one works.
So let's get rid of Tom and clap because this is kind of stupid anyways.
So let's go ahead and see if we can delete it.
And it looks like we got rid of it.
Now let's do something that uses more beats, and more beats per minute.
So let's do 24 Is that like a logical thing and let's make this a higher number like 480 and see if that works.
Okay, so we're at much higher now.
And let's just kind of put I'm gonna turn it off just so there's not too much noise for you guys.
So that's eight.
That's 1216 20.
And then for these last four, we'll do crashes.
Alright, and then let's do bass snare.
Actually, we're going to want to spread these out a little bit, because it's sort of twice as fast as a normal rock beat.
So we'll do bass bass snare.
Take a pause and then we'll do bass bass, snare tech pause, bass, bass snare, and then we'll do Clap, clap, clap at the end.
And we'll do four times at the end.
Let's see what the sound like four times because we're hardcore.
Alright, so I'm gonna save this beef.
I'm just gonna call it out.
You're bored CBT so that's not working.
We need to figure out why our CBT buttons aren't working.
What do we do to mess up the rest of this collide point? Pause.
I think we don't want these all to be LFS because technically they're in the same spots.
Let's see if that solves it.
I think that's it.
causing us strife.
Let's check that out.
Load beat entry rectangles not to find something strange is happening.
Load beat we need to check out why entry rectangle is not defined.
It's coming from Save Menu.
Oh, well, yeah, entry rectangle is not going to be defined.
Because if Save menu is not true, then there's no rect.
So let's come down to the rectangles like this one.
And let's just add something here.
That's if Save menu.
And then we'll put all of this inside of it.
And I think we'll want the same thing for these three, because they're loading only.
So we'll say if load menu.
So we do need to distinguish that we don't want to check for anything with these three buttons, if that is not true, and then hopefully that will take care of it.
So if we load in saving button is not defined.
But why do you care? I thought I have you checked out so you don't care.
Oh, we want all of this inside the same if Save menu.
There we go.
Let's try that load beat Tom and clap.
There it is.
The Beat load in generic rock beat let's load it in.
Yeah, that's hardcore.
Alright, let's just make it 12.
And let's do something stupid.
I don't know it doesn't matter.
Let's try to save this as a longer beat.
Let's save it.
Let's see if we can load in longer beat.
Yeah, I'll go ahead and clear this.
I'll load in the generic rock beat a load in the generic rock beat.
I'll clear it out.
And I'll see if I can load in the longer beat.
And it makes it 12.
So we have the ability to turn off individual channels, we have the ability to play and pause we have the ability to edit while something's active or inactive.
We have the ability to change how many beats are in the loop, we have the ability to save beats, we have the ability to load beats, we have the ability to clear the board.
This is a really cool app.
I had a ton of fun building it.
Obviously it's a challenging tutorial.
I know it's been a really long time.
So if you stuck it out the whole time.
I hope you're enjoying it.
If you have any questions about things we didn't cover or you'd like to see expanded upon, or you tried this yourself and you're running into snags, just let me know about in the comments below.
I'll get back to you as soon as I can.
I hope you enjoyed it.
If you did, please leave a like on the video subscribe to my channel.
It helps me out a ton.
And I post tons of great content just like this every week.
So without any further ado, good luck with your projects and thanks for watching.
Take it easy until next time, bye.