XaiJu
JPDE
JPDE

patreon


Renpy Tutorial 03 - Music, Sound, Audio Channels

INTRODUCTION

Hello thar, Meinos Kaen here… And welcome back to my tutorial video series for making games in Ren’py. You've been showing the series SO much love. Your comments and feedback make my day, so thank you so much!

Before we get into the meat of this video, a recommendation and an announcement. This beginner video series is structured like a class, where you're supposed to have seen previous videos to understand certain basic concepts. Otherwise, the more we cover, the more repetition would be needed, and we'd end up with some huge, bloated videos. So, if you haven't seen the previous two videos, I encourage you to do so before diving into Video Number three.

And for the announcement: I'm happy to announce that I've opened a Discord specifically centered around my Ren'Py Tutorials! I figured, after some people came into my videogame development server for help, that it would be useful to have a dedicated space where you can ask for help, come together, and maybe share your projects! I'd love to see what you're working on. The link is in the description!

And now, without further ado... This video will teach you all the basics you need about using Sound in your game!

First, we'll talk about why music and sound effects are so important and why you should bother at all. Then, we're going to see how to use music and sound effects in a Ren'py script. Next, we'll go over how to make custom Audio Channels to supplement Ren'Py's default ones. And finally, we'll see how to modify the default audio levels for your channels.

Let's go!

WHY SOUND?

If you're approaching Ren'py, chances are that the game you're trying to make is a Visual Novel. Going by the name alone, the focus is on the Art –Visual- and the writing –Novel-. So, in this context, why should you bother learning about sound at all? Other than your dream voice-over for your heroine, or how to apply some stock background music?

It's two-fold. At higher levels, bad sound design can make the difference between a good game and a great game. For beginners, sound design can cover for a lot of rough edges and compensate for unavailability of other types of resources. And if you're watching a beginners tutorial series like this one, you're probably a beginner... So what do I mean by that?

Art pieces, whether it be backgrounds or sprites or graphic user interfaces or CG images cost money –pay your artists and do NOT use Generative AI!- and, also, time. You can throw as much money at an artist as possible but at the end of the day, the money cannot make them go faster.

Also, especially as a beginner or a team that doesn't have a producer or director, you won't be able to properly gauge how many art pieces you need ahead of time. I still struggle with this myself, and I've been doing this for almost a decade now! If you're a beginner dev, do not think that to make a good game you need a huge amount of custom-made art.

Still, beginner or not, you want your game to stand out a little. You want it to have personality... And that's where music and sound effects come in.

First of all, on average there's a LOT more music and sound effects packs available on websites like Itch.io and DLSite than art packs, both free and for sale. Of a great variety of genres, from Fantasy to Slice of Life to Horror, etc... So, from a cost-effect perspective, you can build a much bigger sound library than you would an art library with the same money.

Secondly, you can make amazing atmospheric games even with just sound, very little art, and writing. There's an entire Genre built around this kind of Game Design philosophy, called Sound Novels. It was created by Chun Soft –yes, that Chun Soft- back in the early nineties with the seminal Otogirisou for the Super Famicom, and its two sequels.

The game has recently received an English Patch –or if you just want a second-hand look, there's an amazing video by Dungeon Chill which I've linked in the description-, so if you want to see how the guys behind Danganronpa made history at a time where consoles didn't have enough memory for all those sprite variations, it's a very good case study.

So, in short, if you're a beginner, you'll get much more mileage by trying to make a Sound Novel rather than a Visual Novel... Which is all well and good, but: how the heck do we use Music and Sounds in Ren'py?

USE MUSIC AND SOUNDS

In the previous video, where we went over Image Manipulation, you have seen how Image objects have specific commands which can then be followed by a number of modifiers, which influence the way the commands act. Like when we saw how to display images using transitions. Audio works in a similar way, and there's only two commands you need to keep in mind.

play: this is the command you use when you want to play a sound.

stop: this is the command you use when you want to stop a sound that is playing.

Easy peasy, lemon squeazy 😊 But we obviously need more information on top of that, and the first piece of information we need is the 'Audio Channel' where we want the sound to play.

For those not familiar with the term, let me illustrate like this. Let's say that this rectangle is the audio output of your game. This represents all the sounds coming out of the software and then into your speaker at any given time. The audio output, though, is composed of different channels, each one carrying sound in a different way.

Ren'py has two default audio channels, ready to use, so visually we can split this square into two rectangles: the one on the left is the 'music' audio channel. If you tell Ren'py to play a sound on the music channel, it's going to loop –aka it's going to repeat- forever until we tell Ren'py to stop. The one on the right, instead, is the 'sound' audio channel. If you tell Ren'py to play a sound on the sound channel, it's going to play once and then stop.

Now, let's go grab the lesson materials from the link in the description. It's going to be a Zip file, containing four audio files, contained in three different folders. This is because, just like Images, proper organization of your file structure helps a lot. So, we have the BGM folder –Background Music- containing the 'whimsy.ogg' file. Then we have the SFX folder –Sound Effects- containing the 'punch.ogg' file and the 'shock.ogg' file. Finally, the we have the BGS folder –Background Sound- containing the 'wind.ogg' file.

These are taken from various free asset packs I've found on Itch.io. You can find the links in the description of the video. Anyhow, take all of these, drag them to the audio subfolder in the game folder of your project... And now, it's time to use them!

Go back to our script.rpy file and let's continue the conversation between Penny and Blake. I'm going to write down a little vignette where they go into a full Tsukkomi routine... Then, Penny is going to physically admonish Blake who's going to react with unbridled surprise. Let me show you how the scene plays out without music, first.

Not bad. Not bad at all. But it is a bit dry, isn't it? And that's where music and sound come into effect! First of all, let's play the whimsy track on the music channel, so that we have some fitting musical accompaniment.

We go right here on this line, as I want the music to start playing from the start of the humorous exchange. And thus, I will write the command 'play'... All lower case. Then, the channel 'music' as I want the track to loop continuously... And finally, we need to tell Ren'py what file we want to play.

If you remember from the previous video, similarly to what we did for the images, we want to write down the file path starting from inside the project's game folder. You can either write by memory, if you remember it... Or you can locate the file in the structure tree of Visual Studio code... Hold the shift key... And drag the file to the line where you want it to appear. In this case, remember to remove the reference to the 'game' folder, since Ren'py always automatically starts its search from there. Referencing it again would give us an error.

Good! Now, let's see how it goes~

Ta-daaaa! We got music! It's as simple as that... Although, we can make it even simpler. Just like we did for images, we can define 'audio' objects so that, whenever we want to use a specific sound, we can just call them with defined short names instead of having to write down the file path every single time. So let's do just that!

We'll create a new rpy script file in the audio folder, and we'll call it... audio_script.rpy. And inside, we will now define our four audio files into audio objects like this: first, we write down the command define. Then, we need to specify what kind of object we're defining, which in this case an Audio object. So define... Space... audio, all lowercase... And then, we put down a full stop immediately after.

Now, after this full stop is where we will give this new audio object its name. It works a little differently than defining images, but it's not complex at all, is it? audio, dot, and we will call this first audio object bgm_whimsy, as it refers to the whimsy music audio file. Then, a space, an equal sign, another space and then, between quotes... The file path of the audio clip we want to play. Just like when defining an image.

Now, let's go back to script.rpy... And replace whimsy's extend file-path with the simple object name bgm_whimsy. Let's test it out!

As you can see, it works exactly the same! And you'll now be able to re-utilize this same sound file in any other instance much faster! Let's define the remaining audio-files as well, and then spruce up our scene even more!

We're going to call them sfx_punch... sfx_shock... And bgs_wind... Then, back to the script.rpy, you can guess where I'm going to play these sound effects at... Since this time we're using sound effects, which we want to play once and that's it, we're going to use the sound channel, instead of the music channel.

And to finish it up, we're going to stop the music right after the violent exchange. 😊 Let's test it out!

Everything works properly! The music plays and stops when it's supposed to, and the sounds as well... Huh-oh. Wait... I forgot to use the wind sound... Oooooh, no. We have a probleeeem.

See, I wanted to add some ambient sounds, too. I wanted to add a slight breeze sound playing in the background... On a loop. Thing is, if you start playing a sound on the same channel before the previous sound has stopped playing, the new sound is going to interrupt the previous one. Like this...

See? The music stops, and is replaced by the Wind loop... And now that I think about it, the same thing happened with the sound effects! The punch sound doesn't finish, because the shock sound interrupts it!

So, what do we do? Ren'py only has two default channels, no? To solve this problem, we would need to create new ones...

And that is exactly what we're going to do.

CUSTOM CHANNELS

Before showing you how to create your own, I'm going to show you the custom audio channels that I use in my games and explain why I use... Well... So many of them, yeah? This is because, as I said at the beginning of the video, I love sound design and there are many tricks and effects that you can only do comfortably with custom channels. Also, there are certain type of sounds that I like to confine to specific audio channels for a number of reasons. I have one for emotional reactions, one for voice acting barks, and so on...

This is not something you need to concern yourself with yet, but do keep it in mind for the future. For now, what we're going to create is two simple custom channels. One which we're going to call LoNoise –Loop Noise-, and it's going to be where we're going to play background ambience sounds in loop. Another one, we're going to call sound2, and it's going to be another sound channel, where to play one and done sound effects.

First of all, at the very top, we're going to need to write init... Followed by space... then python... All lower case, and finally colon. This is to tell Ren'py two things: first, that whatever code we write here needs to happen before anything else in the game, hence init (like Initial); second, that what the code we're going to write here is not Ren'py language specific, but more generic python functions, if still related to Ren'py. Not something you need to worry about, but I like to explain everything I write so that you're not confused as to the reasons why I do certain things.

After this, we go on down on a new line –make sure everything you write here is tabbed once to the right- and now it's time for registering our custom channels. First of all, we write renpy. This is to tell the software that the function comes from the renpy list of python functions, it's... An environmental identifier, so to speak. Then, a full stop... music, to tell it that the function is from the ones that deal with audio... Another full stop and finally, the name of the function we want to use: register_channel.

Every time you want to register a custom audio channel, you're going to use this exact function. Now, for the details that are going to change... We want to create a channel which loops sounds, and a sound2 channel which does not loop sounds. How do we differentiate them?

After register_channel, we open round brackets. Then, between quotes, we first write down the name we're going to give to our new channel... Which, we decided to call LoNoise... Then, we add a comma. Next, always between quotes, we need to add the sound mixer the channel is going to use.

Mixers are another concept that will only make sense if you know about how sound design works. All you need to know is that, again, Ren'py has three default ones –the music mixer, the sfx mixer, and the voice mixer- but you can also create new ones right here, when registering new channels. It's what I like to do myself, and it's going to help us do something else later... So we're going to write here 'bgs', thus creating a 'bgs' background sound mixer which, if we want, we will then be able to use in other channels if say, we wanted to make more than one LoNoise channel –as I like to do-.

Last, we want this channel to loop its sounds like in the music channel. To do that... We do nothing. No, seriously. Whenever creating a new channel with this method, the channel will be a looping channel by default. So, for the LoNoise channel, that's all we need to do...

While we need an extra step for creating the sound_2 channel, which we do not want to loop sounds. So, on a second line below, again: renpy dot music dot register_channel... Open quotes... Between quotes, the name of the channel 'sound2'... Comma... The name of the mixer, which will be the default Ren'py one 'sfx'... And then, at the end, after another comma, we add loop=False. This tells Ren'py that this new custom channel should not loop sounds that play on it by default.

And that is it. Congratulations! You've created your very own custom sound channels! Let's put them to the test~

We go back to script.rpy and, where we try and play bgs_wind, we write down LoNoise instead of music... And where we try and play sfx_shock, we will play it on the sound2 channel instead of the default sound channel. Let's see how that plays out!

And here we go~ As you can see –well, as you can hear- the music is still playing out while the wind background ambience starts... And the punch sound effect plays to completion, because the sfx_shock sound effects is now playing on a different channel. Then, when we stop the music, we're left with the wind background ambience alone!

This is all you need to know to properly work with audio in Ren'py! After this, it's just a matter of experimenting, learning how to properly time sound... Although, there are is another thing that, while not strictly necessary, I feel is super-important. The bane of my existence. AUDIO LEVELS.

AUDIO DEFAULTS

You ever listen to a piece of music and, while you like it, you feel like there's something off about it? Like certain instruments are fighting each other for space, and it ends up with certain parts being saturated? Or you can't really hear the voice of the singer properly? Unintelligible levels? Well, that means that the Mixing and Mastering of the track is poor.

Again, sound design stuff, which boils down to: the volumes and frequencies of the various parts of the song aren't properly balanced. This can be a huge issue for videogames, as well. You can have places where the music is too loud while someone is speaking, or the background ambience could be overpowering the sound effects... There are ways where you can fine-tune single sounds you play at any point in a Ren'py game, but for a beginner I feel that it's more useful to teach you how to control your default sound levels.

For this, we're going to go into the options.rpy file. This is a special file that contains a lot of settings that determine under-the-hood workings of your game. Things that, normally, a player won't be able to affect, unless the developer decides to give them that option.

What you need to do here is scroll down to line 43, where you can read 'Sounds and Music', below which you will find three variables which control 'which mixers are show to the player by default'. What that means is that, if you go into the settings menu on the project, you will see three bars which allow the player to control the volume level of the three default mixers of Ren'py: sfx, music, and voice. But only if these variables are all = True.

If I were to turn any of these off like, say, this has_sound variable statement, to False... Then that mixer control bar would disappear. This, though, is only valid for the basic Ren'Py GUI, because custom GUIs may have special preference menus... Anyway, not important!

What's important is that what we can do here is also set-up the various default audio levels of the mixers. Meaning that, when a player first starts up the game, without messing around with the available settings, these are going to be the default loudness at which each sound mixer is going to play files at.

Again, this might seem like a nothing-burger –especially since nowadays players expect the option of being able to toy around with sound settings at their leisure- but trust me when I say that, the more you play around with sound and directing a scene, the more you're going to get a feeling for specific sound levels and specific ways they interact with each other. So, instead of having to tell Ren'py every single time the volume at which you want certain type of sounds to play, it pays huge dividends to have some defaults.

So, how do we do that? We go below the three standard statements, leaving them alone –unless you want your players to be unable to control any of the default mixers- and on a new line, we write: default –which, is pretty self-explanatory, we're going to define the default value of a modifiable variable-... Then space, and we add preferences... Followed by a dot... then, 'volume', to tell Ren'py that we're assigning default value to a variable of the type volume of the group preferences... Of what mixer, though?

So we add another dot... And then let's say... music. We're giving the default value of the music mixer. Which, in my case, I want to be loud but not too loud. Thus, we add a space... Then an equal sign... Another space, and then we add a float between 0.0 and 1.0 which indicates the desired default level... For music, I'm going to use 0.66. Which means that, out of the maximum loudness possible for this mixer, the default level is going to be roughly two thirds of that.

And that is it. Rinse and repeat for the other two mixers that we are currently using. We have no voice acting, so we can leave that alone... Heck, why don't we hide it altogether? Let's turn this to false... Then, the default sfx one for sound and sound2... default, space, preferences... Dot... volume... dot... sfx... equal sign... For sound effects, I like to have them always be sharp and on average louder than anything else, so let's set them to 0.75.

And finally, the custom BGS mixer we created when we made our custom LoNoise channel. Background ambience should be, as the name says, in the background. It should be something that you can detect but not exactly hear... So, I like to keep it at something like 0.33. A third of the maximum loudness for this mixer. Let's save and then, go back to our scene... And see how it plays out!

As you can see/hear, the scene plays out the same but without adding any further qualifiers or information on the single instances, the sound levels of everything happening on screen are now rebalanced. If I want to make changes to single plays of certain sounds, that is possible, but as that would be the exception to the rule, having control over the default sound levels is going to save you a lot of time.

CONCLUSIONS

And that. Is. That. All you need to know to get started with music and sound in Ren'py! One last thing I want you to remember is that, even if you adjust the levels via code, if your base sound files don't have roughly the same volume, that's going to skew your experience playing different files. So keep that in mind and maybe get a free audio editor like Audacity to modify them.

Also, you might have noticed that all the files I've been using are of the ogg type... There's a number of reasons for that, first and foremost that the size of an ogg file is much inferior to a wav, but it also has other features which we may cover in a future video.

For now, thank you for your attention! I invite you to join our new Ren'Py School Discord server, maybe follow me on BlueSky and, if you like, check out our games on Itch and maybe support us on Patreon and Ko-Fi!

I'll see you in the next video, which will complete this small set of four to teach you all the Basics of Ren'py! After that, we'll go into more specific subjects... And I have a few ideas about letting you all influence what comes next for the channel in the future.

Ciao!

Renpy Tutorial 03 - Music, Sound, Audio Channels

More Creators