With using just SDL2 and no SDL2_Mixer, how can we play two or more WAV sounds simultaneously?
The current build of our new project can play only one WAV sound at a time?
Please look at our code on GitHub below and suggest a solution to the above issue, thanks!
You can do it using
SDL_MixAudioFormat() but bear in mind that the two WAVs that you mix together need to be in the same format (same sample rate, same number of channels, same number of bits per channel). Whilst you could do a format conversion in real time using
SDL_ConvertAudio() personally I would always prefer to do the conversion ‘offline’ and supply matching WAVs with the app.
What becomes more interesting is mixing a second WAV ‘asynchronously’ with a currently-playing WAV (such as adding sound effects on top of music) without using SDL_mixer. For a long time I thought that was impossible, but it can be done with the proviso that there’s a race hazard (I asked a question about this here recently). It also seems not to work properly when using WASAPI in Windows so I force the audio driver to directsound in that case.
It’s amazing what you can do without using SDL_mixer if you try hard enough!
Thanks for the reply…
Sound rather complicated.
Is there a code same or a tutorial somewhere on the web for playing multiple WAVs simultaneously?
(using just vanilla SDL2)
Not really, it’s only using the functions as they are documented. I’d post my code except that it’s in BBC BASIC which I suspect is not the language you would prefer!
rtrussell, could you show your code for ‘asynchronously’ wav playing such as adding sound effects on top of music?
In pseudo-code terms:
Play the first sound, e.g. music:
SDL_QueueAudio(device, first_sound, first_length);
To mix in the second sound, e.g. sound effect:
size = SDL_GetQueuedAudioSize(device);
ptr = first_sound + first_length - size;
SDL_MixAudioFormat(ptr, second_sound, format, second_length, volume);
SDL_QueueAudio(device, ptr, size);
This works very well for me, but there are a couple of points to note:
There must be at least as much of the ‘first’ sound not yet played as the length of the ‘second’ sound.
There is a potential race hazard between
SDL_ClearQueuedAudio(); if the background process removes another chunk of audio between these two calls the mix will misbehave. In an ideal world there would be an SDL function which clears the queued audio and returns how much has been cleared.
Any improvements to this?
None that I have found. It still works very nicely for me, with the caveats mentioned earlier in the thread. It also looks as though whatever was stopping it working with the WASAPI backend might have been fixed, because I’ve just tried it without forcing the driver to directsound, and now it works!
Still struggling with above…
I found below working example but it’s in plain C and not C++
I tried to convert above example to C++ and it builds and runs but does not play any audio?
You can see our project on GitHub below:
Any help would be appreciated, thanks!
Sorry, I don’t use C++. However my code above is so simple (6 lines to mix a sound effect with currently-playing music) I would not have expected any issues to arise from conversion.
Was not talking about your code above.
We found an example of multi-channel audio with just SDL2 but it’s in C and not C++:
We tried to convert the above C code to C++ but it does not work?
Our project is hosted on GitHub below:
Just looking for help with our incorrect implementation, thanks!
Making some progress…
I have below code in the main.cpp file:
SDL_LoadWAV(“data/audio/BGM-IDE1.wav”, &wavSpec, &wavBuffer, &wavLength);
SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, 0);
SDL_QueueAudio(deviceId, wavBuffer, wavLength);
SDL_LoadWAV(“data/audio/SFX-MenuClick.wav”, &wavSpec, &wavBuffer, &wavLength);
Uint32 sizeAudio = SDL_GetQueuedAudioSize(deviceId);
Uint8 * ptr = wavBuffer + wavLength - sizeAudio;
SDL_MixAudioFormat(ptr, wavBuffer, NULL, wavLength, SDL_MIX_MAXVOLUME);
SDL_QueueAudio(deviceId, ptr, sizeAudio);
First WAV plays fine(it’s music).
Second WAV does not play though?
Got it working:
Had to change below:
SDL_MixAudioFormat(ptr, wavBuffer, AUDIO_S16, wavLength, SDL_MIX_MAXVOLUME);