Making a Game - Using the Music - EP 27


Video Tutorial

Aims of this Tutorial

  • Import the music into Godot.
  • Set up the audio server in Godot for centralised music.
  • Programmatically change the music that is playing.

Importing the Music

This part is fairly straight forward. First you need to go into your DAW (eg Ardour) and export to a format that Godot can read. I recommend Ogg Vorbis as this is what I used, so you can follow along easily. If you are using music from the public domain or do not have access to the DAW file, then do not panic, you can use ffmpeg to convert the file with the following command.

ffmpeg -i "input_file" "output_file.ogg"

Now, you simply need to move this audio file into your project directory. I recommend putting this in a subdirectory that will help you organise your project. I put my one in Audio/Music but you could use a different scheme if you prefer. When you head back into Godot, it will automatically import them for you. You can them select them to edit some basic settings in the inspector such as whether they loop (true for music) and a loop offset (used if there is silence that you want to cut out of the loop).

Setting up the Audio Server

Godot has a really simple way of handling audio. On the bottom of the editor, you will see a tab called 'Audio'. If you click on that, it will show you the busses in your audio server. At the minute there is only one, called 'Master'. This bus is the most important bus, because everything leads to this bus to be played out the speakers. However, we want our music and sound effects to be controlled separately, so we need to make a new bus that sends its output to the master bus.

To make a new bus, click on the plus icon in the top right of the audio pane and call it something sensible like 'Music'. We can then have a look at any effects that you might want to add. If you click on the effects dropdown on the new music bus, you can see all the effects available. While these will not be of the same quality that we used in Ardour, they can be altered while playing the game (eg low pass filter if you go underwater).

Finally we need something to actually tell the audio server that we want to play music. To do that, head into the root node scene and create a new child node of type AudioStreamPlayer. You will notice that there are 2D and 3D versions of this node which can be used to get a directional sound including the Doppler effect (think about an ambulance driving by). We do not want this for music, unless you want your music playing through in game speakers. In that node, make sure that it is outputting to our new music bus, so we can control all music from that bus.

Controlling the Music

We now need to make a script on the new node (we could do this in the root node, but it is a little cleaner to keep things separate where possible). This script needs to have all the possible music files loaded in, ready to be played. In order to play them, it has a function that will change them using a dictionary to point to which music file we want to play. We also need a mute function for testing, so make sure you go back into your input map in the project settings and add a new action 'mute' and give it a sensible keybinding. The code for this node is as follows.

extends AudioStreamPlayer

var mute_status : bool = false

var main_theme : AudioStreamOGGVorbis = preload("res://Audio/Music/SpaceMainTheme_r1_session.ogg")
var combat_theme : AudioStreamOGGVorbis = preload("res://Audio/Music/CombatThemeLBRY_r1_session.ogg")

var music_dict = {"main" : main_theme, "combat" : combat_theme}

func switch_theme(name : String) -> void:
	if name in music_dict.keys():
		stream = music_dict[name]
		get_parent().console_print("Could not find music of name, " + name)
	playing = true

func _process(delta : float) -> void:
	if Input.is_action_just_pressed("mute") :
		if mute_status:
			AudioServer.set_bus_mute(AudioServer.get_bus_index("Master"), false)
			AudioServer.set_bus_mute(AudioServer.get_bus_index("Master"), true)
		mute_status = !mute_status

Note that we check that a song exists before we try to call it, just incase a node requests that we play 'conbat' for instance, and we will get a message in the logs letting us know that there is a typo.