Godot Engine Tutorial Part 4 – Playing Sound FX and Music

This tutorial is available as an HD video here.

Today we are going to look at using audio with Godot.  If you’ve used other game engines you will find the process is probably quite a bit different and perhaps a little unintuitive but in the end rather simple and quite power.  It is a bit of a multistep process so let’s jump right in.

For this example you are going to need a couple audio files.  Personally I get most of the audio files for my tutorials from a site called http://www.freesound.org/.  Now a moment about audio formats.

The Two Kinds of Audio

There are two audio types in Godot ( and many other game engines ).  Samples and Streams.  A sample is an uncompressed piece of sound that is loaded into memory.  Samples take up more memory but a great deal less processing power.  In Godot you create samples by importing them as WAV files.  Streams on the other hand are instead compressed audio files (think MP3), often much longer in duration.  These you simply copy into your project, Godot supports MPC and Ogg Vorbis formats. 

Generally samples are used for in game quick sound effects, while streams are used for background music.  There is a pretty good chance your audio isn’t in WAV, Ogg or MPC format.  If it isn’t, I highly recommend the free program Audacity for converting between formats.

Playing an Audio Sample

As I said earlier, samples are uncompressed audio files generally used for sound effects and it’s a multistep process loading and playing one.  Its also quite common to play multiple of the sample sample at once.  Ok, let’s look at that process.

First you need to create a SamplePlayer.  This is a node you can add to your scene.  There are 3 kinds of players, SamplePlayer, SamplePlayer2D and SpatialSamplePlayer.  They all accomplish the same thing, however 2D has additional stereo support and can be positioned in your 2D world, while Spatial enables you to position your audio source in 3D to simulate positional audio.  In this tutorial we are just going to use the simple SamplePlayer.  We may cover the other two in later tutorials.

Creating the SamplePlayer Node

Add a new SamplePlayer node to your scene:

image

Creating a new SampleLibrary

Now we need to create a Sample library.  With your SamplePlayer selected in the Scene panel, in Inspector locate Samples, drop in down and select New SampleLibrary:

image

Now drop it down again and select Edit:

image

This will change your active view to the samples library view.  Note, the tabs above ( 2d, 3d, etc ) will not navigate you out of this screen currently.  To get back to your 2D scene view, select a different node in the Scene panel to the right.

image

Importing an Audio Sample

We can now use this window to add our samples to the library… guess we need a sample.  For that you use the Import menu.  Select Import->Audio Sample:

image

This will bring up an Import Audio Samples dialog like so:

image

Under source, navigate to the WAV file you want to import.  For target path select the location within your project you want it to reside.  Under options you have several configuration settings, such as changing the amount of data used/fidelity of your sound ( Max Rate Hz ), making it Mono vs Stereo or forcing it to be 8bit, which is a really low fidelity, single channel but tiny audio file.  For now just use the default settings.  When you click Import a new “smp” file will be added to your project:

image

Adding Sample to Audio Library

Now that we have our sample, we need to add it to our library.  You can use the same sample in multiple libraries.  In the Edit Sample window select the open icon:

image

Select your newly imported sample.  It should now appear in the list like so:

image

Here you can preview the sample, change it’s default volume using dB (decibel) or change it’s pitch using the PScale value.  You can add multiple samples to the sample library.  The yellow blob you see in the middle of the screen is the waveform of the audio… there are two of them because this is a stereo example.  As you can see by the fact they are identical waveforms, this is actually really wasteful, so you would be best to save the file size and import this as a mono sample instead!

Playing an Audio Sample using SamplePlayer

Now that we have an SampleLibrary with a sample in it, we can now go ahead and play it.  Let’s add a script to our SamplePlayer node that will automatically play the sound when we begin.  It’s incredibly simple, like so:

extends SamplePlayer
func _ready():
   play("siren")

Yeah… that’s it.  You simply call the play method of SamplePlayer and pass in the name as defined in the Sample Library.

Of course, rarely are you going to have a SamplePlayer play it’s own sounds.  What is much more likely is you would add a SamplePlayer to the base of your scene tree, then call it from child nodes within the scene.  Don’t worry, that is equally simple… let’s do it!

Add a Button Node to your scene, attach a script to it, then hit the Connections icon and create a default handler for the “pressed()” connection.

image
image

Generally you wouldn’t use the SamplePlayer as the root scene node, but that’s what I’ve got so I went with it…  Now in your button handler, you can get a reference to the SamplePlayer using:

extends Button
func _ready():
   pass
func _on_Button_pressed():
    get_tree().get_root().get_node("SamplePlayer").play("siren")

One important thing to be aware of…  the value passed into play() is case sensitive!  So if I passed in “Siren” it wouldn’t play anything!  So basically playing a sample is simply a matter of getting a reference to the SamplePlayer node and calling the play method.

So… that’s how you play a single sound… how do you play multiple at once… well, that’s a matter of voices.  A Voice can be thought of as a playing instance of a single sound.  If you want multiple sounds to play at once, you need multiple voices in your SamplePlayer.  You can set that value in the Inspector of the player, like so:

image

Now when you run the application, each time you click the button a new version of your sound effect will start playing concurrent to the previous version.  What if you only want a single instance of a sound effect to play at a time?  Well that can be done too…  when you call play() there is an optional second parameter that tells Godot wether the sound is unqiue or not.  Set it to true, like so:

get_tree().get_root().get_node("SamplePlayer").play("siren",true)

And each time your press the button the sound effect will instead start over.

One final critical thing to understand is how to manipulate ( stop, pause, change volume, etc… ) a single instance of a sound playing.  This is done using Voice IDs, once of which is returned when you play a sample.  So the following example plays a sound and immediately sets it’s volume to 50%:

func _on_Button_pressed():
   var player = get_tree().get_root().get_node("SamplePlayer")
   var voiceID = player.play("siren")
   player.set_volume(voiceID, 0.5)

So you used the voice ID to interact with already running samples.  These only last as along as the sample is playing.

Playing Music

Now let’s look at streaming a file instead.  The process is very similar, but instead you add a StreamPlayer node:

image

Now copy an MPC or OGG file into your project file folder using Windows Explorer or Mac Finder.  Now in Inspector with StreamPlayer selected, locate the Stream property and select the appropriate type, I’m using AudioStreamOGGVorbis:

image

Now drop it down again and select Load:

image

Select the file you copied into your project.  Attach a script to a Node in your Scene… for demo reasons I’m just adding it to the StreamPlayer itself.  Then you can use the code:

extends StreamPlayer
func _ready():
   self.play()

You don’t actually need code to accomplish this.  If you want the StreamPlayer to play it’s song automatically, you can simply set the Autoplay property:

image

Now one really common thing to do in games is to play a different song after the current song finished playing… let’s take a look at how you can accomplish this:

extends StreamPlayer
var song1
var song2
var currentSong = song1
func _ready():
   set_process(true)
   song2 = load("song2.ogg")
   
func _process(delta):
   if(self.is_playing() != true):
      if(self.get_stream() == song1):
         self.set_stream(song2)
      else:
         self.set_stream(song1)
      self.play()

The Video Version

Programming Godot Tutorial 2D Engine


Scroll to Top