
Play music and sound with ALmixer
In this tutorial, we use ALmixer to play music and sound. Almixer is a simple library that use OpenAl to play sounds.
- SDL2, Almixer
ALmixer is a cross-platform audio library that sits on top of OpenAL, designed to make sound playback simpler and more flexible—similar in spirit to SDL_mixer but with enhanced capabilities.
What Is ALmixer?
- Simplified API: Provides an easy-to-use interface inspired by SDL_mixer, letting you play and manage audio without wrestling with OpenAL sources, buffers, and queueing.
- Format Support via SDL_sound: Uses SDL_sound to decode formats like WAV, MP3, AAC, MP4, OGG, and more.
- Unified Playback Model: Unlike SDL_mixer, ALmixer merges “music” and “sound” into a single API, letting you preload or stream any audio type freely. This means multiple streamed audio sources can play simultaneously.
In this tutorial the goal is to play music and sound with ALmixer.
Setting up
Before starting to play music and sound with ALmixer you will need to:
- Download OpenAL
- Download and build libogg and libvorbis
- Download and build ALmixer with OGG support (
ALMIXER_USE_OGG_VORBIS_DECODER)
Playing music
When everything is configured, you will need an OGG music to play. I will use this one in the tutorial: music.ogg
The first thing to do is load the audio data. The music file can be big so we don’t want to load everything in memory, for that we use the function:
ALmixer_LoadStream(const char* file_name,
ALuint buffer_size,
ALuint max_queue_buffers,
ALuint num_startup_buffers,
ALuint suggested_number_of_buffers_to_queue_per_update_pass,
ALuint access_data)We can simply take the default parameters:
ALmixer_Data *music_data = ALmixer_LoadStream("music.ogg",
ALMIXER_DEFAULT_BUFFERSIZE,
ALMIXER_DEFAULT_QUEUE_BUFFERS,
ALMIXER_DEFAULT_STARTUP_BUFFERS,
ALMIXER_DEFAULT_BUFFERS_TO_QUEUE_PER_UPDATE_PASS,
AL_FALSE);To play the music we will need to use a channel, to find a free channel you can use:
ALint channel_music = ALmixer_FindFreeChannel(0);The first parameter is the starting channel, ALmixer will find the first available channel starting from this channel.
Good, we can play the song!
ALmixer_PlayChannel(channel_music, music_data, 0);The third parameter is the number of loops you want to play the song. If you set the number of loops to -1, the song loops forever.
You can set the volume for the channel with:
ALmixer_SetVolumeChannel(channel_music, 80);In this example I want to be able to pause the music when pressing the ‘P’ key, and resume the channel when pressing the ‘R’ key.
In the event loop you will need to call ALmixer_PauseChannel and ALmixer_ResumeChannel:
if (e.key.keysym.sym == SDLK_p) {
ALmixer_PauseChannel(channel_music);
}
else if (e.key.keysym.sym == SDLK_r) {
ALmixer_ResumeChannel(channel_music);
}If you want to know when the song is finished you can set a callback function with:
ALmixer_SetPlaybackFinishedCallback(Internal_SoundFinished_CallbackIntercept, NULL);In this case, Internal_SoundFinished_CallbackIntercept is the callback function:
void Internal_SoundFinished_CallbackIntercept(ALint which_channel,
ALuint al_source,
ALmixer_Data* almixer_data,
ALboolean finished_naturally,
void* user_data) {
std::cout << "sound finished : " << which_channel << "\n";
}Playing sound
A sound is simply a really short noise or music, so we can load the small file in memory.
In this example we will use the sound: kick.ogg
ALmixer_Data* sound_data = ALmixer_LoadAll("kick.ogg", AL_FALSE);The rest of the code is similar to the previous example:
ALint channel_sound = ALmixer_FindFreeChannel(0);
ALmixer_PlayChannel(channel_sound, sound_data, 0);Full source code
void Internal_SoundFinished_CallbackIntercept(ALint which_channel, ALuint al_source, ALmixer_Data* almixer_data, ALboolean finished_naturally, void* user_data) {
std::cout << "sound finished : " << which_channel << "\n";
}
int main(int argc, char* argv[]) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
ALmixer_Init(ALMIXER_DEFAULT_FREQUENCY, ALMIXER_DEFAULT_NUM_SOURCES, ALMIXER_DEFAULT_REFRESH);
SDL_Window* window = SDL_CreateWindow("Playing music and sound with ALmixer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_OPENGL);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
ALmixer_Data *music_data = ALmixer_LoadStream("music.ogg", ALMIXER_DEFAULT_BUFFERSIZE, ALMIXER_DEFAULT_QUEUE_BUFFERS, ALMIXER_DEFAULT_STARTUP_BUFFERS, ALMIXER_DEFAULT_BUFFERS_TO_QUEUE_PER_UPDATE_PASS, AL_FALSE);
ALint channel_music = ALmixer_FindFreeChannel(0);
ALmixer_PlayChannel(channel_music, music_data, 0);
ALmixer_SetVolumeChannel(channel_music, 80);
ALmixer_SetPlaybackFinishedCallback(Internal_SoundFinished_CallbackIntercept, NULL);
ALmixer_Data* sound_data = ALmixer_LoadAll("kick.ogg", AL_FALSE);
ALint channel_sound = ALmixer_FindFreeChannel(0);
while (true) {
SDL_Event e;
if (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
break;
}
if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym == SDLK_p) {
ALmixer_PauseChannel(channel_music);
}
else if (e.key.keysym.sym == SDLK_r) {
ALmixer_ResumeChannel(channel_music);
}
else if (e.key.keysym.sym == SDLK_k) {
ALmixer_PlayChannel(channel_sound, sound_data, 0);
}
}
}
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
ALmixer_Quit();
SDL_Quit();
return 0;
}You can download the project: PlayingMusic.7z