[SOLVED] SDL2_mixer: No free channels available

Howdy folks,

EDIT: Solved, I just needed to Mix_AllocateChannels(some_high_number);. Apparently “channels” in Mix_OpenAudio corresponds directly to mono/stereo/surround/etc. Stereo provides 8 “channels” which are seemingly software-defined, not hardware defined. But you can also allocate these “software channels” in greater number. I feel like this naming schema is pretty confusing. Anyway, it works now.

I’m trying to use SDL2_mixer for my game, and maybe I’m doing something wrong here, but seems like I can’t play very many samples at once. I’ve tried tweaking my MixOpenAudio parameters, but it doesn’t seem to help. I’ve boiled down my example to a short and simple C file.

#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>

int main(int argc, char** argv) {
    // Initialize SDL2 mixer
    int flags = MIX_INIT_OGG;
    int initted = Mix_Init(flags);
    if ((initted & flags) != flags) {
        printf("Failed to initialize SDL2 mixer: %s\n", Mix_GetError());
        return 1;
    }

    // Open the audio device
    int channels = 2;
    int chunksize = 1024;
    if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, channels, chunksize) < 0) {
        printf("Failed to open audio device: %s\n", Mix_GetError());
        return 1;
    }

    // Load the OGG files
    Mix_Chunk* effects[14];
	effects[0] = Mix_LoadWAV("sfx_shotgun_shoot.ogg");
	effects[1] = Mix_LoadWAV("sfx_enemy_gib.ogg");
	effects[2] = Mix_LoadWAV("sfx_enemy_hit.ogg");
	effects[3] = Mix_LoadWAV("sfx_enemy_hound_attack.ogg");
	effects[4] = Mix_LoadWAV("sfx_grenade_bounce.ogg");
	effects[5] = Mix_LoadWAV("sfx_grenade_explode.ogg");
	effects[6] = Mix_LoadWAV("sfx_grenade_shoot.ogg");
	effects[7] = Mix_LoadWAV("sfx_hurt.ogg");
	effects[8] = Mix_LoadWAV("sfx_nailgun_hit.ogg");
	effects[9] = Mix_LoadWAV("sfx_nailgun_shoot.ogg");
	effects[10] = Mix_LoadWAV("sfx_no_ammo.ogg");
	effects[11] = Mix_LoadWAV("sfx_pickup.ogg");
	effects[12] = Mix_LoadWAV("sfx_plasma_shoot.ogg");
	effects[13] = Mix_LoadWAV("sfx_shotgun_reload.ogg");

    // Play the sound effects
    for (int i = 0; i < 14; i++) {
        int channel = Mix_PlayChannel(-1, effects[i], 0);
        if (channel == -1) {
            printf("Failed to play effect: %s\n", Mix_GetError());
        }
    }

    // Wait for the sound effects to finish
    SDL_Delay(5000); // wait for 5 seconds

    // Free the loaded files
    for (int i = 0; i < 10; i++) {
        Mix_FreeChunk(effects[i]);
    }

    // Close the audio device
    Mix_CloseAudio();

    // Quit SDL2 mixer
    Mix_Quit();

    return 0;
}

This will play my sound effects, but a few of them fail to play:

$ gcc main.c -lSDL2 -lSDL2_mixer && ./a.out 
Failed to play effect: No free channels available
Failed to play effect: No free channels available
Failed to play effect: No free channels available
Failed to play effect: No free channels available
Failed to play effect: No free channels available
Failed to play effect: No free channels available

Now, I don’t really know a ton about how digital audio works, but I’ve been going off of this from the docs:

The audio device channels are generally 1 for mono output, or 2 for stereo, but the brave can try surround sound configs with 4 (quad), 6 (5.1), 7 (6.1) or 8 (7.1).

The audio device's chunk size is the number of sample frames (one sample per frame for mono output, two samples per frame in a stereo setup, etc) that are fed to the device at once. The lower the number, the lower the latency, but you risk dropouts if it gets too low. 2048 is often a reasonable default

Ok, so channels is gonna be a static 2 for me here, and the higher I set the chunk size, the more sounds I should be able to play at once? But 512, 1024, 2048, 4096, they all produce the same amount of errors.

Could anyone shed some light on how this works? The files are all pretty small and short. I also tried reducing the frequency and bitrates by half (to 24KHz, and 64Kbps), but it always seems to error out after exactly 8 requests to play chunks.

files:

 14K  sfx_enemy_gib.ogg
6.2K  sfx_enemy_hit.ogg
 12K  sfx_enemy_hound_attack.ogg
9.5K  sfx_grenade_bounce.ogg
 21K  sfx_grenade_explode.ogg
 12K  sfx_grenade_shoot.ogg
 11K  sfx_hurt.ogg
6.5K  sfx_nailgun_hit.ogg
9.4K  sfx_nailgun_shoot.ogg
4.6K  sfx_no_ammo.ogg
9.0K  sfx_pickup.ogg
 13K  sfx_plasma_shoot.ogg
6.8K  sfx_shotgun_reload.ogg
 14K  sfx_shotgun_shoot.ogg
 
sfx_enemy_gib.ogg:          Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_enemy_hit.ogg:          Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_enemy_hound_attack.ogg: Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_grenade_bounce.ogg:     Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_grenade_explode.ogg:    Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_grenade_shoot.ogg:      Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_hurt.ogg:               Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_nailgun_hit.ogg:        Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_nailgun_shoot.ogg:      Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_no_ammo.ogg:            Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_pickup.ogg:             Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_plasma_shoot.ogg:       Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_shotgun_reload.ogg:     Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps
sfx_shotgun_shoot.ogg:      Ogg data, Vorbis audio, stereo, 48000 Hz, ~112000 bps

Thanks,
– Ben

If you need stereo sound, always open audio subsystem with two channels. Then, allocate enough channels (actualy tracks) using the Mix_AllocateChannels function. The more sounds you need to play simultaneously, the more tracks you need to allocate (one sound per track). You can allocate even hundreds of tracks.

The larger the chunk size, the bigger data packet is sent to the sound card at once:

The audio device’s chunk size is the number of sample frames (one sample per frame for mono output, two samples per frame in a stereo setup, etc) that are fed to the device at once. The lower the number, the lower the latency, but you risk dropouts if it gets too low. 2048 is often a reasonable default, but your app might want to experiment with 1024