PySDL2: Playing a sound from a WAV file take two - using SDL2_mixer

1 minute read

Yesterday I wrote about playing a WAVE sound using basic PySDL2. I also mentioned that I thought that using the SDL2_mixer extension (or sdl2.sdlmixer as it is called in PySDL2) would probably be easier. What I didn’t anticipate was how much easier it would be. Using sdl2.sdlmixer more than halved the lines of code necessary to play the wav file, most importantly by removing the requirement to create a callback function to feed frames to the sound buffer.

The caveat is that you have to install the SDL2_mixer extension, of course. Just follow the instructions from the PySDL2 documentation, the simplest is to download the pre-built binaries. Then you have to make PySDL2 find the extension libraries. The installation guide talks about installing to the system or modifying PYTHONPATH, but the preferred method is actually to store the libraries in a custom folder and setting PYSDL2_DLL_PATH to the full path of that folder.

Once the extension is installed and working the code is simply this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
try:
    from sdl2 import *
    from sdl2.ext import Resources
    from sdl2.ext.compat import byteify
    from sdl2.sdlmixer import *
except ImportError:
    import traceback
    traceback.print_exc()
    sys.exit(1)

RESOURCES = Resources(__file__, "assets")

if SDL_Init(SDL_INIT_AUDIO) != 0:
    raise RuntimeError("Cannot initialize audio system: {}".format(SDL_GetError()))

if Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024):
    raise RuntimeError("Cannot open mixed audio: {}".format(Mix_GetError()))

sound_file = RESOURCES.get_path("tada.wav")
sample = Mix_LoadWAV(byteify(sound_file, "utf-8"))
if sample is None:
    raise RuntimeError("Cannot open audio file: {}".format(Mix_GetError()))
channel = Mix_PlayChannel(-1, sample, 0)
if channel == -1:
    raise RuntimeError("Cannot play sample: {}".format(Mix_GetError()))

while Mix_Playing(channel):
    SDL_Delay(100)

Mix_CloseAudio()
SDL_Quit(SDL_INIT_AUDIO)

The code is simply initialize the audio system using standard SDL_Init then initialize the mixer API with Mix_OpenAudio before loading the wav file. This is different than the basic SDL2 API where you load the file first and then open the audio device. Finally, play the sound with Mix_PlayChannel and wait until it has completed.