Simple GBA music player
1. INTRODUCTION
I finally completed a small project of mine: a simple GBA music player in Butano.
The code is available on my GitHub, so you can download and try it out.
Before starting, I would like to make a disclaimer: I am not a programmer, so I have limited knowledge of coding.
I am trying to learn, but I won't be aiming for the same precision as professional programmers.
This was the first step of a bigger project that I hope to bring to YouTube as soon as possible. I plan to take some video game OSTs and modify their sound using the Pokémon Emerald soundfont.
Basically, it will feel like those OSTs were part of the Pokémon Generation 3 games.
However, the interesting part is that I am actually doing more than that.
Indeed, I am not only working on the music, but I'm putting it directly into my GBA music player, meaning that every song is actually playable like it was in an actual GBA game!
Since my code is on GitHub and it's simple, and heavily inspired by the Butano Music example, I decided to write this post also to explain some of the code.
This mostly serves as a reminder for myself of the progress I made, but it could also be of help to someone else.
2. EXPLAINING THE CODE
This simple GBA music player is written in C++ with Butano, featuring music control and tempo change.
The image below is a screenshot of the GBA player in action, showing everything that you can do with it.
2.1 MUSIC CONTROLS
There are only two controls: pressing A stops the music or resumes it (if it had been stopped before), pressing START restarts the music.
The code is so simple that it explains itself. The only worthy thing to mention is the is_paused boolean variable, used to check if the music has been stopped before or not. If the music was stopped (is_paused is true), then pressing A resumes the music, and sets is_paused to false (indeed, the music is playing again now). The opposite happens if A is pressed when the music is playing. Since the music starts playing by default as soon as we open the .gba file, is_paused is initialized as false (bool is_paused = false).
// Stop/Resume music if A pressed
if(bn::keypad::a_pressed())
{
if(is_paused)
{
bn::music::resume();
is_paused = false;
}
else
{
bn::music::pause();
is_paused = true;
}
}
The START command is simple, too. If START is pressed, the music plays again from the beginning. The line tempo = 1 is used to reset the tempo of the song if it was previously accelerated or slowed down.
Of course, if the song was reset, there's no need to display the tempo, because we all know it's 1.
//reset music if START is pressed
if(bn::keypad::start_pressed())
{
bn::music_items::music.play(0.5);
tempo=1;
}
2.2 TEMPO CHANGE
The tempo of the song can be controlled: pressing L will slow it down (up to 0.5x), while pressing R will speed it up (up to 2x).
To achieve this, I had to introduce the variable tempo set to 1 (bn::fixed tempo = 1.0).
When the button L is pressed, tempo is now equal to tempo - 0.1. In addition to that, to avoid errors, I noticed that it couldn't go any lower than 0.5, so I added a new rule: if tempo had a value inferior to 0.5, it would reset automatically to 0.5 (the minimum value).
//slower tempo
if(bn::keypad::l_pressed())
{
tempo -= 0.1;
if (tempo < 0.5)
{
tempo = 0.5;
}
}
In the same way, when you press R, the tempo is equal to tempo + 0.1.
For the same reason stated above, I had to write a rule that made sure the value of tempo was over 2.0 (the maximum value).
//faster tempo
if(bn::keypad::r_pressed())
{
tempo += 0.1;
if(tempo > 2.0)
{
tempo = 2.0;
}
}
The tempo change actually happens when the variable old_tempo (bn::fixed old_tempo = 1.0) has a different value from the tempo variable.
if (old_tempo != tempo)
{
bn::music::set_tempo(tempo);
old_tempo = tempo;
}
2.3 CD ANIMATION
There's a simple CD Animation that I built. I am trying to learn some pixel art as well (I made my logo, and the art in my GBA SP keypad demo, for example), but I am currently not so good at it. Drawing a CD was really easy, and I added some light shades on it to give a sense of movement during the animation.
Being a CD, I simply decided to make it rotate on itself. To do that, I introduced the variable "angle" (int angle = 0) and used bn::sprite.set_rotation_angle(angle).
To end the cycle, if the value of the variable angle becomes equal to or greater than 360, the value is reset to 0. Thanks to this, we get a full 360-degree rotation.
angle += 2;
if (angle >= 360)
{
angle -= 360;
}
2.4 TEXT GENERATION
This was the hardest part because I had never worked with text before. It turns out it's not complicated, at least for easy tasks like this one.
It mostly came down to creating two string vectors, which could contain "Tempo: " and the value of the tempo variable.
This only happens when the tempo variable has a different value from the old_tempo variable, and if tempo is not equal to 1 (same case as 2.2).
I used bn::sprite_text_generator and a vector named text_sprites to hold the generated characters.
if (old_tempo != tempo)
{
bn::music::set_tempo(tempo);
text_sprites.clear();
if (tempo != 1.0)
{
bn::string<32> text_string = "Tempo: ";
text_string += bn::to_string<16>(tempo);
text_generator.generate(20, -66, text_string, text_sprites);
}
old_tempo = tempo;
}
2.5 INTERCHANGABILITY OF MUSIC
This isn't really an explanation, but rather something I'd like to highlight. The interesting part of this code is also that every song file in a GBA-compatible format for Butano can be played.
The only condition for this to happen is to have only 1 file named "music" in the audio folder of the Butano project. This is because, in the code, the music file is referred to as "music".
Example:
bn::music_items::music.play(0.5)
This is really handy for me to try out songs and see if they actually play in-game.
3. CONCLUSION
Most of the code was already in the Butano Music example, so I haven't done much but assemble everything. It wasn't hard, but it was a good way to learn, especially for someone like me, who's just starting.
I really hope this post was helpful to someone, and stay tuned for the upcoming videos!

Comments
Post a Comment