Sound effects for Pygame
By flreey · Published · Code tested with WAV files on pygame 2.6.1 (SDL 2.28.4), Python 3.11, macOS, on 2026-10-31
Your Pygame game runs, but it is silent. Below is an arcade set (pickup, jump, hit, power-up, laser, explosion, game over) and the code that plays it, which we ran with this set's WAV files before publishing. The part most tutorials skip is at the end: what happens when ten pickups land in the same frame. The sounds are CC0, so the game can be sold.
The whole thing as a game you can run, with mute, volume and a headless test: pygame-arcade on GitHub.
| Play | Event | Sound | Length | Download |
|---|---|---|---|---|
| Coin / item pickupDouble-Chime 8-Bit Coin Pickup 52 (No Reverb) | Double-Chime 8-Bit Coin Pickup 52 (No Reverb) | 1.1 s | ||
| JumpClassic Rising 8-Bit Video Game Jump 49 | Classic Rising 8-Bit Video Game Jump 49 | 0.33 s | ||
| Hit / damageShort Zap Retro Game Hit 02 | Short Zap Retro Game Hit 02 | 0.13 s | ||
| Power-upMajor-Key 8-Bit Power-Up 50 | Major-Key 8-Bit Power-Up 50 | 0.30 s | ||
| Shoot / laserPiercing 8-Bit Laser Shot 51 | Piercing 8-Bit Laser Shot 51 | 0.73 s | ||
| ExplosionShort Burst 8-Bit Explosion 65 | Short Burst 8-Bit Explosion 65 | 0.41 s | ||
| Game overSlow 8-Bit Game Over Jingle 65 | Slow 8-Bit Game Over Jingle 65 | 0.38 s |
1. Put the files next to your code
From the folder with your game's .py file:
npx sfxmint add --set retro-game --format wav --out assets/soundsThat writes pickup.wav, jump.wav, hit.wav, powerup.wav, laser.wav, explosion.wav and gameover.wav, plus a SOUNDS.md with each sound's page and license. WAV comes with the download pack ($9.90 for 30 days, one payment), so this command takes a pack's key in SFXMINT_API_KEY. A puzzle or platformer game may fit the puzzle or platformer set better; the command takes their names too.
No pack? pygame.mixer.Sound documents OGG as well as WAV, and this set comes as free OGG:
npx sfxmint add --set retro-game --format ogg --out assets/soundsThen change .wav to .ogg in the code below. We ran that code with WAV, and a library MP3, WAV and OGG each load and play in pygame.mixer.Sound on pygame 2.6.1; the pygame-arcade example's test also checks that its OGG files load. A whole set takes a free account's API key in SFXMINT_API_KEY; without a key you get the first 5 sounds. No Node.js? Use the download buttons in the table and rename the files the same way.
2. Load once, play by name
from pathlib import Path
import pygame
pygame.mixer.pre_init(44100, -16, 2, 512) # before init; matters on pygame 1.9
pygame.init()
pygame.mixer.set_num_channels(16) # see "pitfalls" below
SOUND_DIR = Path(__file__).parent / "assets" / "sounds"
SOUNDS = {
name: pygame.mixer.Sound(SOUND_DIR / f"{name}.wav")
for name in ("jump", "pickup", "hit", "powerup", "explosion", "gameover")
}
def play(name):
SOUNDS[name].play()
# In the game loop:
# if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
# player.jump(); play("jump")
# if player.rect.colliderect(coin.rect):
# play("pickup")Loading the six files took under a millisecond in our run, so doing it at startup costs nothing; doing it inside the loop reads the disk every frame. The path is built from the script's folder, so the game also runs when started from somewhere else.
3. Looping music or ambience
npx sfxmint add rain --format ogg --out assets/soundspygame.mixer.music.load(SOUND_DIR / "rain.ogg")
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1) # -1 loops forever
# Later: pygame.mixer.music.fadeout(1500)pygame.mixer.music streams one long file and does not use the effect channels. Other loops: forest, wind, dark ambience.
4. A volume setting
def set_sfx_volume(value): # 0.0 to 1.0, from your settings menu
for sound in SOUNDS.values():
sound.set_volume(value)
def set_music_volume(value):
pygame.mixer.music.set_volume(value)5. Pitfalls we hit while testing
- Sounds are dropped, silently. With the default 8 channels, ten pickups played in the same frame started only 7; the other calls returned
Noneand made no sound and no error. That is why the code raises the count to 16. To keep one important sound from being dropped, reserve a channel for it:pygame.mixer.set_reserved(1)and play it withpygame.mixer.Channel(0).play(sound). get_length()is the file, not the sound. It returned 1.00 s for the jump, whose page says 0.35 s of sound in a 1 s file; the rest is silence. Do not time animations or cooldowns fromget_length(): use the length of sound each page lists.- The browser needs OGG. pygbag's wiki asks for every audio file in OGG, not WAV or MP3. Download the set again with
--format ogg, or keep WAV on desktop and switch by platform:
import sys
EXT = "ogg" if sys.platform == "emscripten" else "wav"
SOUNDS = {name: pygame.mixer.Sound(SOUND_DIR / f"{name}.{EXT}") for name in ("jump", "pickup")}In the browser, like every web game, sound starts only after the player's first click or key.
6. If ChatGPT or Claude wrote your game
Put the files in assets/sounds first, then give it this:
Add sound effects to my Pygame game using the sound files in assets/sounds
(jump, pickup, hit, powerup, explosion, gameover). Load each file once at startup into a dict,
call pygame.mixer.set_num_channels(16) after pygame.init(), and play the right sound at each
event in the game loop. Add a volume setting for effects and one for music.With Claude Code, Cursor or Codex, the assistant can fetch the files itself: see add sound effects with a coding assistant.
Questions
WAV, OGG or MP3 for pygame.mixer.Sound?
On pygame 2.6 all three load into a Sound. WAV is the safe default for desktop; a browser build with pygbag needs OGG. WAV comes with the download pack ($9.90 for 30 days, one payment); MP3 and, for older sounds, OGG download free.
Why is there a delay before each sound?
On pygame 1.9 the mixer's default buffer was 4096 samples, which you can hear; pygame.mixer.pre_init(44100, -16, 2, 512) before pygame.init() fixes it, and pygame 2 already defaults to 512. If a sound still starts late, the file begins with silence: each sound page shows how long its audible part is.
Do I need str() around a pathlib.Path?
Not on pygame 2.6: pygame.mixer.Sound and pygame.mixer.music.load both took a Path in our test. str() does no harm if you support older versions.
Can I use these sounds in a game I sell?
Yes, they are CC0. See CC0 sound effects for commercial games for what that allows and the AI disclosure Steam and itch.io ask for.