This is the third article in the Forge series. In the previous post, we learned how to render textures to the screen. Now, let’s add another layer of life to our projects: audio.
Forge comes with a simple yet powerful Audio API, making it easy to load, play, and control both music and sound effects.
Understanding Forge Audio 🎧
Forge provides two main types of audio objects:
| Audio.Music | Streamed from disk during playback | Background music or long tracks (30+ seconds) |
| Audio.Sound | Fully loaded into memory | Short effects (clicks, jumps, UI sounds) |
Loading audio takes a lot of memory, that’s why tis distinction helps optimize performance. Large files are streamed to save memory, while small recurring effects are kept ready for instant playback to reduce latency.
Project Setup 🧱
As always, we’ll start by creating a new project using the Forge Starter Template:
git clone https://github.com/ForgeLeaf/ForgeStarterTemplate.git
cd ForgeStarterTemplate
Now, as usual, create your assets folder within the project root directory, and you’re ready to download both assets and place move them into the assets folder.
You can download the ZIP file here (Credits are listed below!)
The Hero Immortal.mp3 file is our music and the Click_Soft_00.wav is our sound effect.
Your assets folder should look like this:

Creating our Variables 📖
As usual, we have to define our assets within our code. For large games, I’d recommend having a structured and optimized asset manager, but for now… We’ll simply declare our objects within the Application struct 😁.
So, just import the github.com/ForgeLeaf/Forge/Audio package, run go mod tidy and declare these two variables in the Application struct:
type Application struct {
music *Audio.Music
sound *Audio.Sound
}
Loading our Music 🎵
Ok, now that we’ve declared our music and sound, we’ll first focus on loading the music object. As usual, we go to our Create() method.
This time we have to keep in mind that our audio is large and we don’t want to let the full game await the loading of our audio objects, that’s why Forge allows you to asynchronously load your audio objects, we do that by placing our calls to Audio.NewMusic(...) and Audio.NewSound(...) in a goroutine.
So, it should look like this for your music:
func (application *Application) Create(driver *Forge.Driver) {
go func() {
application.music, _ = Audio.NewMusic("assets/Hero Immortal.mp3")
}()
}
Just like our texture constructor method, the audio constructors return an audio object and an optional error. We’ll ignore the error for now 🤫
Now, we’d like to instantly play our music after it loads and we’ll add this code snippet into our goroutine:
application.music.SetLooping(true)
application.music.SetVolume(0.5)
application.music.Play()
Let’s break it down:
- We set the music mode to looping, so the music never stops.
- We set the volume to 50% to not play it loud.
- We tell the music object to start streaming and playing the audio.
Before running the code: When working with music objects, remember to close the music object when the game exists, so go to your application destroy callback, the Destroy() method, and add this snippet:
func (application *Application) Destroy(driver *Forge.Driver) {
application.music.Close()
}
You’ll end up with something like this:
It’s nice to see our game come to live 🤗
Loading our Sound 🎤
Similar to our music, we’ll most of the times want to load our sounds asynchronously in a goroutine. So, let’s jump to our existing goroutine and add this line after constructing our music object:
application.sound, _ = Audio.NewSound("assets/Click_Soft_00.wav")
We’ll ignore the optional error and just pretend that everything works ideally out-of-the-box. Unlike a music object, a sound has its memory managed by the go garbage-collector, so we don’t have to close or dispose anything manually when our application exists.
Now, let’s make our sound play whenever we touch the screen… I know we haven’t discussed input yet but let’s make it fun and we’ll pretend that you already know what a MouseButtonCallback is 🙃
Right after our goroutine call in Create(), we put this self explanatory code snippet:
driver.Input.SetMouseButtonCallback(func(button Input.MouseButton, action Input.Action, modifiers Input.ModifierKey, x, y float32) {
if button == Input.MouseButtonLeft && action == Input.ActionPress {
application.sound.Play(1)
}
})
Let’s break it down quickly:
- We register a callback whenever a mouse button action occurs.
- When the callback is called, we check if the button is
Input.MouseButtonLeftand action isInput.ActionPressedto validate that the user pressed the left mouse button. - We play our sound with volume set to 100%.
You’ll end up with something like this:
And that’s it 🎉
You now know how to create and use audio objects in Forge!
The Full Example Code 🪄
package main
import (
"runtime"
"github.com/ForgeLeaf/Forge"
"github.com/ForgeLeaf/Forge/Audio"
"github.com/ForgeLeaf/Forge/Input"
)
type Application struct {
music *Audio.Music
sound *Audio.Sound
}
func (application *Application) Create(driver *Forge.Driver) {
go func() {
application.music, _ = Audio.NewMusic("assets/Hero Immortal.mp3")
application.sound, _ = Audio.NewSound("assets/Click_Soft_00.wav")
application.music.SetLooping(true)
application.music.SetVolume(0.5)
application.music.Play()
}()
driver.Input.SetMouseButtonCallback(func(button Input.MouseButton, action Input.Action, modifiers Input.ModifierKey, x, y float32) {
if button == Input.MouseButtonLeft && action == Input.ActionPress {
application.sound.Play(1)
}
})
}
func (application *Application) Render(driver *Forge.Driver, delta float32) {}
func (application *Application) Resize(driver *Forge.Driver, width, height float32) {}
func (application *Application) Destroy(driver *Forge.Driver) {
application.music.Close()
}
func init() {
runtime.LockOSThread()
}
func main() {
if err := Forge.RunSafe(&Application{}, Forge.DefaultDesktopConfig()); err != nil {
panic(err)
}
}
Compare it to your version and tell me if it works! That’s it! You’ve successfully drawn your first texture with Forge. If you’ve faced any issues, please message me using the form below.
You can find the repository for this tutorial here: https://github.com/ForgeLeaf/WorkingWithAudio-Forge
Audio Credits🔗
🎵 Music: “Hero Immortal” by Trevor Lentz, available on OpenGameArt.org.
🔊 Sound Effect: “Click_Soft_00.wav” by Little Robot Sound Factory, available on OpenGameArt.org.
Common Issues
If you’re getting a black screen:
- Check if you imported the
image/pngpackage. - Check if you’re rendering within
batch.Begin()andbatch.End(). - Check if you’re applying the viewport projection to the batch.
If the code isn’t compiling:
- Check if you’ve misspelled any imports.
- Run
go mod tidyand rebuild. - Clear IDE cache.
- Check for syntax errors.
If your program is crashing before rendering anything:
- Check whether you’ve imported the correct
go-glversion or not (Correct one isgo-gl/gl/v3.3-core/gl).
If you’re facing any other issues, contact me below!



