There does not exist a really good solution for loading, playing and looping sounds, that doesn't add dependencies to your project. Many games can get away with panning for left/right, and maybe some kind of way to fade sounds in or out. These requirements do not sound like too much to ask! But apparently they are since the only available pre-made solutions are ginormous libraries or non-free.
Some existing solutions are FMOD, OpenAL, SDL_Mixer. Adding in dependencies like this comes with strings. FMOD might not be free for many developers, OpenAL might be difficult to use, etc. In general adding in dependencies feels bad and sucks for a variety of reasons.
Wouldn't it be great to find a single-header we can plop into our game that immediately supports our simple sound needs? Now one exists! It's called
tinysound.
tinysound is a single file C header that supports loading, playing, looping, fading, panning, and delayed playing of sounds. It includes a very high-performance mixer that uses SIMD intrinsics. Sounds can be loaded off disk, or directly from memory. tinysound uses a single malloc/free call! All memory, except for the tinysound context, can be explicitly managed. WAV files and OGG files are supported.
Sounds too good to be true? Well it is.
Currently it only runs on Windows and OSX/iOS (so no Linux). If someone wanted to contribute to an open source project I've already prepared tinysound for porting, so adding another platform should take very minimal effort. UPDATE: Actually it runs everywhere SDL can run! tinysound has a native Win implementation, a native OSX/iOS implementation, and also contains a port to SDL for running on Linux environments. This is great since SDL can act as a thing layer basically doing a couple memcpys and a callback. See the header for more details.
Hope someone finds this library useful! I sure do and use it in my own game project. Cheers
Example:
#define TS_IMPLEMENTATION
#include "tinysound.h"
void LowLevelAPI( tsContext* ctx )
{
// load a couple sounds
tsLoadedSound airlock = tsLoadWAV( "airlock.wav" );
tsLoadedSound jump = tsLoadWAV( "jump.wav" );
// make playable instances
tsPlayingSound s0 = tsMakePlayingSound( &airlock );
tsPlayingSound s1 = tsMakePlayingSound( &jump );
// setup a loop and play it
tsLoopSound( &s0, 1 );
tsInsertSound( ctx, &s0 );
while ( 1 )
{
if ( GetAsyncKeyState( VK_ESCAPE ) )
break;
// play the sound
if ( GetAsyncKeyState( VK_SPACE ) )
tsInsertSound( ctx, &s1 );
tsMix( ctx );
}
}
int main( )
{
HWND hwnd = GetConsoleWindow( );
tsContext* ctx = tsMakeContext( hwnd, 48100, 15, 1, 0 );
LowLevelAPI( );
tsShutdownContext( ctx );
return 0;
}