Copyright © Jari Komppa
SoLoud is an easy to use, free, portable c/c++ audio engine for games.
The engine has been designed to make simple things easy, while not making harder things impossible. Here's a code snippet that initializes the library, loads a sample and plays it:
// Declare some variables SoLoud::Soloud soloud; // Engine core SoLoud::Wav sample; // One sample // Initialize SoLoud (automatic back-end selection) soloud.init(); sample.load("pew_pew.wav"); // Load a wave file soloud.play(sample); // Play it
The primary form of use the interface is designed for is "fire and forget" audio. In many games, most of the time you don't need to modify a sound's parameters on the fly - you just find an event, like an explosion, and trigger a sound effect. SoLoud handles the rest.
If you need to alter some aspect of the sound after the fact, the "play" function returns a handle you can use. For example:
int handle = soloud.play(sample); // Play the sound soloud.setVolume(handle, 0.5f); // Set volume; 1.0f is "normal" soloud.setPan(handle, -0.2f); // Set pan; -1 is left, 1 is right soloud.setRelativePlaySpeed(handle, 0.9f);// Play a bit slower; 1.0f is normal
If the sound doesn't exist anymore (either it's ended or you've played so many sounds at once it's channel has been taken over by some other sound), the handle is still safe to use - it just doesn't do anything.
There's also a pure "C" version of the whole API which can even be used from non-c languages by using SoLoud as an DLL, such as Python.
SoLoud is released under the ZLib/LibPNG license. That means, among other things, that:
Basically the only things the license forbids are suing the authors, or claiming that you made SoLoud. If you redistribute the source code, the license needs to be there. But not with the binaries.
Parts of the SoLoud package were not made by me, and those either have a similar license, or more permissive (such as Unlicense, CC0, WTFPL or Public Domain).
While SoLoud's usage has been designed to be very easy, it's still packed with powerful functionality. Some of the features include:
SoLoud quite probably doesn't have all the features you'd find in a commercial library like FMOD or WWISE. There's no artist tools, and only limited engine integration.
It quite probably isn't as fast. As of this writing, it has limited specialized SSE optimizations. It contains no hand-written assembly.
It definitely doesn't come with the support you get from a commercial library.
While softare using SoLoud has already shipped on all current-gen consoles (as of 2018), the backends needed for those are not included with SoLoud due to SDK license issues. New backends are easy to write, however.
If you're planning to make a multi-million budgeted console game, this library is (probably) not for you. Feel free to try it though :-)
This quick start is for c++ developers. If you're using SoLoud with some other environment SoLoud supports, you may want to skip this and look at the chapter that covers your environment (such as Python).
First, you need to download SoLoud sources. You can find the downloads on the http://soloud-audio.com/downloads.html page.
There's a few ways to include SoLoud to your project.
You can, for example, include all the SoLoud source files to your project, define one or more of the backend defines (see table below), and you're good to go.
A bit more structured way is to use GENie / premake4 to create the build files, and build a static library for your compiler / environment.
Note that the Windows DLL only exports the "C" API, which may not be what you want - it's primarily meant for foreign interface use.
If you're including the sources directly to your project, You'll need the core files, at least one backend, and at least one audio source. For example, for wav file playing, you'll need the files from audiosource/wav.
The current list of back-ends is:
|WITH_MINIAUDIO||MiniAudio cross-platform audio backend|
|WITH_SDL||SDL or SDL2 via runtime dyndll linking|
|WITH_SDL1||SDL1 via runtime dyndll linking|
|WITH_SDL2||SDL2 via runtime dyndll linking|
|WITH_SDL_STATIC||SDL via normal static linking|
|WITH_SDL2||SDL or SDL2 via runtime dyndll linking|
|WITH_SDL2_STATIC||SDL2 via normal static linking|
|WITH_PORTAUDIO||Portaudio via runtime dyndll linking|
|WITH_OPENAL||OpenAL via runtime dyndll linking (high latency)|
|WITH_XAUDIO2||XAudio2 via normal linking|
|WITH_VITA_HOMEBREW||Sony Vita homebrew backend|
|WITH_NOSOUND||Nosound audio device|
|WITH_NULL||Special use "no backend"|
The backend with no audio device may seem odd, but that can be used to call SoLoud's mix function manually, which can be useful in some cases such as LibRetro.
In order to use a certain feature of SoLoud, you need to include its header file. You might have, for instance:
#include "soloud.h" #include "soloud_wav.h"
You need at least the SoLoud engine core, and one or more of the audio source variables. If you're using five different sound effect wav files, you need five SoLoud::Wav objects. You can play one object any number of times, even on top of itself.
Where to place these is up to you. Globals work, as do allocation from heap, including in a class as members, etc. Stack is probably a bad idea, but I'm not stopping you.
SoLoud::Soloud gSoloud; // SoLoud engine SoLoud::Wav gWave; // One wave file
In your application, once you have your framework up (for instance after your SDL_Init call), include a call to initialize SoLoud.
gSoloud.init(); // Initialize SoLoud
The call has a bunch of optional parameters if you'd rather pick the replay back-end and its parameters yourself; the default should work for most cases.
This step varies from one audio source to another, but basically you'll load your wave files here.
gWave.load("pew_pew.wav"); // Load a wave
Now you're ready to play the sounds. Place playing commands wherever you need sound to be played.
gSoloud.play(gWave); // Play the wave
Note that you can play the same sound several times, and it doesn't cut itself off (but if that's what you want, there's an option for that too).
You can adjust various things about the sound you're playing if you take the handle.
int x = gSoloud.play(gWave); // Grab the handle gSoloud.setPan(x, -0.2f); // Use handle to adjust panning
Read the soloud.h header file (or this documentation) for further things you can do.
After you've done, remember to clean up. If you don't, the audio thread may do stupid things while the application is shutting down.
gSoloud.deinit(); // Clean up!
And you're done!
Some useful notes:
Most calls to SoLoud also return some kind of return code which may help you diagnose potential problems. When loading wave files, for instance, you may want to check if the file is actually found.
Many of the calls also have additional optional parameters, and there are also alternate calls to do (almost) the same thing (Wav::load() and WavStream::loadToMem() as an example).
Finally, SoLoud has been designed so that you can ignore most of the return values. If there's an error state, such as wav file failing to load, further calls, like trying to play the wav file that didn't load, will simply do nothing.
Currently, SoLoud includes support for various wav formats including 8, 16, 32 bit, float, double, pcmcia, etc., as well as Ogg Vorbis and MP3 files. Not all variants and features are supported, so you may experience some issues with strange files. As time has progressed, the libraries SoLoud uses to read these files have improved, but they are still not the reference libraries, so some strange variants may exist out there.
Additionally, SoLoud comes with a speech synthesizer based on rsynth, another primitive speech synth, a retro sound effect synthesizer Sfxr, replayer for MONOTONE PC-speaker tracker music, a replayer for C64 SID and Commodore plus/4 TED music, and a Commodore VIC emulator too.
Finally, SoLoud can use Openmpt through DLL interface, which can play 669, amf, ams, dbm, digi, dmf, dsm, far, gdm, ice, imf, it, itp, j2b, m15, mdl, med, mid, mo3, mod, mptm, mt2, mtm, okt, plm, psm, ptm, s3m, stm, ult, umx, wow and xm. (Note that Openmpt has a more restrictive license than SoLoud).
The interface for audio sources is relatively simple, so new formats and noise generators, as well as audio filters, can be made.
An example sin/saw/triangle/square generator is also available, as part of the "piano" example.
All of the above can also be fed through series of filters for additional fun.
There's no external library dependencies (apart from stdlib). However, to get audio out of your speakers, a back-end is needed. Back-ends that currently exist (but are not limited to) include SDL, windows multimedia, oss, alsa and portaudio, and SoLoud has been designed so that making new back-ends would be as painless as possible.
Yes! This DLL can be used from non-c++ environments through the "C" interface. SoLoud comes with wrappers for Python, Ruby, c#, BlitzMax and others.
A fennec fox. Google it. They're cute!
There's a google group, at http://groups.google.com/d/forum/soloud
Main development occurs on GitHub, at https://github.com/jarikomppa/soloud and the issue tracker is in use.
Finally, there's #soloud on ircnet, if you want to pop by.
No, instead you get documentation written by an actual human being. Granted, some function descriptions may be a bit terse or repetitive, but that's what you would have gotten from doxygen too..
I'm aware there are other forks of libmodplug, which may be in better shape than the one used by SoLoud by default. However, those forks use more restrictive licenses, which (while still liberal) would require changes in SoLoud licensing. At the moment, you don't need to mention the use of SoLoud anywhere if you don't want to.
That said, nothing's stopping you from compiling a version of SoLoud that uses another fork of libmodplug.
Originally SoLoud used a public domain fork of modplug, but as time went on it became increasingly clear that instead of supporting SoLoud the author would have had to support modplug. At the same time better supported forks of modplug existed, so SoLoud was divorced from the modplug code, while making it possible to use modplug if needed.
Currently, no. Pull requests are welcome =)
All joking aside, there's no simple place to plug this in currently. It's a TODO item for the future.
Yes. SoLoud supports 1, 2, 4, 5.1 and 7.1 configurations.
The way multi-speaker system is implemented in SoLoud, it would be relatively easy to add any number of speakers, but having more output channels also adds overhead. Most people will only ever use stereo output.
Some directories have been omitted from the overview graph to make it more manageable.
Note that documentation is not included in the SoLoud distribution, and is available separately in various formats.
|scripts||Scripts used to automate wrapper code generation. Unless you're adding features to SoLoud, you won't need to touch them.|
|include||All of the include files are kept in this single directory.|
|bin||Pre-built binaries of the SoLoud demos for windows.|
|glue||All the glue libraries for various environments, like rpgmaker, c#, python, d, ruby, etc.|
|build||The GENie / premake script that can be used to generate build scripts for various IDEs or a gnu makefile.|
|demos||SoLoud's demos showing how to use SoLoud's various features.|
|src||Source code for SoLoud itself|
|contrib||Additional files that are not maintained by SoLoud project itself, such as cmakefiles, but may be useful to some people.|
|src/audiosource||SoLoud's audio sources, such as speech, wav, etc.|
|src/backend||Back-end interfaces, such as sdl, alsa, wasapi, etc.|
|src/c_api||The generated c-api code, which is used to create the SoLoud DLL, can be found here.|
|src/core||SoLoud's core source files.|
|src/filter||SoLoud's filters, such as lo-fi, biquad resonant filter, etc.|
|src/tools||Some command-line tools under the src/tools directory. Most of these are for SoLoud development.|
Most of the demos are based on SDL2 and use some common code based on Ocornut's Dear ImGui library. This is to make the source for the demo itself mostly about SoLoud and not about putting pixels on the screen, while having an easy to use UI for the demos.
|demos/android||Demo for Android operating system.|
|demos/c_test||Test for the c-api.|
|demos/common||Common code for graphical demos.|
|demos/emscripten||Scripts for compiling for web browsers with Emscripten|
|demos/enumerate||Enumerate all backends, show information.|
|demos/env||Environmental audio demo.|
|demos/glue||Some tiny examples for different foreign interfaces (cs, rpgmaker, etc).|
|demos/megademo||Compilation of many smaller demos showing off various features.|
|demos/null||Null driver example (using SoLoud without audio output).|
|demos/piano||Simple musical instrument using SoLoud.|
|demos/welcome||Slightly more complex example than simplest.|
SoLoud comes with a GENie script. GENie is a fork of premake4, and the script may still be compatible with the latest premake.
If you want to build SoLoud as static library (instead of including the source files in your project) this can be handy.
GENie can be downloaded from https://github.com/bkaradzic/genie. Premake can be downloaded from http://industriousone.com/premake.
Unfortunately, GENie cannot magically figure out where your libraries may be installed, so you may have to edit the genie.lua file. The lines to edit can be found at the very beginning of the file, with the following defaults:
local sdl_root = "/libraries/sdl" local sdl2_root = "/libraries/sdl2" local portmidi_root = "/libraries/portmidi" local dxsdk_root = "C:/Program Files (x86)/Microsoft ..." local portaudio_root = "/libraries/portaudio" local openal_root = "/libraries/openal"
You will most likely want to edit at least the sdl2_root variable. After your edits, you can run GENie to generate makefiles or the IDE project files of your preference, such as:
The current version (984) supports cmake, GNU makefiles (gmake), ninja, qbs, vs2010, vs2012, vs2013, vs2015, vs2017, xcode8, xcode9, xcode10.
You can also use one or more of the optional parameters to change the build behavior.
|soloud-devel||Shorthand for options used while developing SoLoud|
|with-common-backends||Includes common backends in build|
|with-coreaudio||Include OS X CoreAudio backend in build|
|with-jack||Include JACK backend in build|
|with-jack-only||Only include JACK backend in build|
|with-miniaudio||Include MiniAudio in build|
|with-miniaudio-only||Only include MiniAudio in build|
|with-native-only||Only native backends (winmm/oss) in build (default)|
|with-nosound||Include nosound backend in build|
|with-openal||Include OpenAL backend in build|
|with-portaudio||Include PortAudio backend in build|
|with-sdl||Include SDL backend in build|
|with-sdl-only||Only include sdl in build|
|with-sdl2||Include SDL2 backend in build|
|with-sdl2-only||Only include sdl2 in build|
|with-sdl2static-only||Only include sdl2 that doesn't use dyndll in build|
|with-sdlstatic-only||Only include sdl that doesn't use dyndll in build|
|with-tools||Include (optional) tools in build|
|with-vita-homebrew-only||Only include PS Vita homebrew backend in build|
|with-wasapi||Include WASAPI backend in build|
|with-xaudio2||Include XAudio2 backend in build|
So for example, in order to build SoLoud with sdl2static and tools on vs2013, use:
genie --with-sdl2static-only --with-tools vs2013
SoLoud, like everything else, stands on the shoulders of giants; however, care has been taken to only incorporate source code that is under liberal licenses, namely ZLib/LibPNG, CC0 or public domain, or similar, like WTFPL or Unlicense, where you don't need to include mention of the code in your documentation or splash screens or any such nonsense.
Any patches submitted to SoLoud must agree to be under compatible licenses.
SoLoud proper is licensed under the ZLib/LibPNG license. The code is a clean-room implementation with no outside sources used.
SoLoud audio engine Copyright (c) 2013-2020 Jari Komppa This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.
The OGG support in the Wav and WavStream sound sources is based on stb_vorbis by Sean Barrett, and it's in the public domain. You can find more information (and latest version) at http://nothings.org/stb_vorbis/
The MP3 support in the Wav and Wavstream sound sources is based on dr_mp3.h by David Reid, and released under Unlicense. dr_mp3.h itself is based on minimp3 is released under CC0 public domain license.
Various wav file formats are loaded using dr_wav.h by David Reid, which is released under Unlicense.
The speech synth is based on rsynth by the late Nick Ing-Simmons (et al). He described the legal status as:
This is a text to speech system produced by integrating various pieces of code and tables of data, which are all (I believe) in the public domain.
Since then, the rsynth source code has passed legal checks by several open source organizations, so it "should" be pretty safe.
The primary copyright claims seem to have to do with text-to-speech dictionary use, which I've removed completely.
I've done some serious refactoring, clean-up and feature removal on the source, as all I need is "a" free, simple speech synth, not a "good" speech synth. Since I've removed a bunch of stuff, this is probably safer public domain release than the original.
I'm placing my changes in public domain as well, or if that's not acceptable for you, then CC0: http://creativecommons.org/publicdomain/zero/1.0/.
The SoLoud interface files (soloud_speech.*) are under the same ZLib/LibPNG license as the other SoLoud bits.
The vizsn speech synthesizer is copyright Ville-Matias Heikkilä, released under WTFPL (in short, "do what you want to").
FFT calculation is based on fftreal by Laurent de Soras, under WTFPL, which lets you do whatever you want with it.
The sfxr sound effects synthesizer is by Tomas Pettersson, re-licensed under zlib/libpng license by permission.
Copyright (c) 2014 Jari Komppa Based on code (c) by Tomas Pettersson, re-licensed under zlib by permission This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.
The RPGMaker wrapper generator contains code copied from the Ruby standard library. This is permitted by the rule 4 of the Ruby license:
Ruby is copyrighted free software by Yukihiro Matsumoto <email@example.com>. You can redistribute it and/or modify it under either the terms of the 2-clause BSDL (see the file BSDL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
In any case, the RPGMaker wrapper does not claim to be Ruby or part of Ruby, and the wrapper generator and the wrapper itself is public and freely available, so that license should be covered many times over.
The TED and SID soundchip emulation as well as tool to generate the register write dumps is based on tedplay (c) 2012 Attila Grosz, used under Unlicense:
This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to <http://unlicense.org/>
The VIC 6560/6561 sound chip emulator is Copyright (c) 2015 Petri Hakkinen, and released under zlib/libpng license:
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.
SoLoud does not include Openmpt in itself, but can use it through a DLL. If you don't need it, you don't need to include the DLL either. If you DO need to use it, please look up its license.
Based on code by Jezar at Dreampoint, June 2000 http://www.dreampoint.co.uk, which was placed under public domain.
Note that the version of FreeVerb included in SoLoud is based on the original, public domain release, and not the GPL-licensed FreeVerb3.
SoLoud uses two kinds of classes for the sounds. Audio sources contain all the information related to the sound in question, such as wave sample data, while audio instances contain information about an "instance" of the sound.
As an analogue, if you think of an old vinyl record, the audio source is the record, and you can put as many playheads - the instances - on the record. All of the playheads can also move at different speeds, output to a different pan position and volume, as well as different filter settings.
SoLoud itself "only" performs audio mixing, resource handling and bookkeeping. For it to be useful, it needs one or more sound source and a back end. Some other audio systems use the term 'sink' for the back-ends (as in audio source and audio sink).
Examples of back-ends would be winmm, oss, portaudio, wasapi and SDL audio. SoLoud comes with several back-ends, and is designed to make back-ends relatively easy to implement.
Different back-ends have different characteristics, such as how much latency they introduce.
One audio stream can contain one or more channels. Typical audio sources are either mono (containing one channel) or stereo (containing two channels), but surround sound audio sources may practically have any number of channels.
In module music (such as mod, s3m, xm, it), "channel" means one of the concurrent sounds played, regardless of speaker configuration. Confusing? Yes.
SoLoud can play audio from several sound sources at once (or, in fact, several times from the same sound source at the same time). Each of these sound instances is a "voice". The number of concurrent voices is limited, as having unlimited voices would cause performance issues, as well as lead to unnecessary clipping.
The default number of concurrent voices - maximum number of "streams" - is 16, but this can be adjusted at runtime. The hard maximum number is 4095, but if more are required, SoLoud can be modified to support more. But seriously, if you need more than 4095 sounds at once, you're probably going to make some serious changes in any case.
If all channels are already playing and the application requests another sound to play, SoLoud finds the oldest voice and kills it. Since this may be your background music, you can protect channels from being killed by using the soloud.setProtect() call.
SoLoud also supports virtual voices, so things are a bit more complicated - basically you can have thousands of voices playing, but only the most audible ones are actually played.
SoLoud lets you play way more voices than will actually be played to the user. This can be useful if you, for instance, populate a 3d world with hundreds of audio sources.
SoLoud will sort the voices based on their current volume level and only mixes the most audible sounds. The number of active voices can be set at runtime. Protected voices are always played.
The maximum number of virtual voices is currently 1024, but can be increased up to a hard limit of 4095 by editing soloud.h and recompiling. Higher virtual voice counts than that will require some refactoring.
Sometimes it is important to be able to command several voices at the same time so that they are synchronized; for instance, when cross-fading between two versions of the same song.
Even if you try to unpause the two voices at the same time, it's possible, due to the multithreaded nature of audio, that the audio engine interrupts you between these two calls and your sounds get unpaused to different audio buffers.
SoLoud's solution to this are voice groups. Voice groups can be commanded the same way as single voices, but instead of affecting just one voice, SoLoud performs the command on all of the voices in the group in one atomic operation.
Audio hardware always has a limited dynamic range. If you think of a signed 16-bit variable, for instance, you can only store values from -32768 to 23767 in it; if you try to put values outside this range in, things tend to break. Same goes for audio.
SoLoud handles all audio as floats, but performs clipping before passing the samples out, so all values are in the -1..1 range. There's two ways SoLoud can perform the clipping; the most straightforward is simply to set all values outside this range to the border value, or alternatively a roundoff calculation can be performed, which "compresses" the loud sounds. The more quiet sounds are largely unchanged, while the loud end gets less precision. The roundoff clipper is used by default.
The roundoff clipper does, however, alter the signal and thus "damages" the sound. A more proper way of doing things would be to use the basic clipper and adjust the global volume to avoid clipping. The roundoff clipper is, however, easier to use.
The real world has continuous signals, which would require infinite amount of storage to store (unless you can figure out some kind of complicated mathematical formula that represents the signal). So, we store discrete samples of signals instead. These samples have traditionally been 8, 16 or 24 bit, but high-end audio is tending towards floating point samples.
SoLoud also uses floating point samples internally. First and foremost, it makes everything much simpler, and second, modern computing devices (even mobile!) have become fast enough that this is not really a performance issue anymore.
Floating point samples also take more space than, for instance, 16 bit samples, but memory and storage sizes have also grown enough to make this a feasible approach. Nothing stops the audio sources from keeping data in a more "compressed" format and performing on-the-fly conversion to float, if memory requirements are a concern.
The sample rate represents the number of samples used, per second. Typical sample rates are 8000Hz, 22050Hz, 44100Hz and 48000Hz. Higher the sample rates mean clearer sound, but also bigger files, more memory and higher processing power requirements.
Due to limitations in human hearing, 44100Hz is generally considered sufficient. Some audiophiles disagree, but then again, some audiophiles buy gold-plated USB cables.
Hertz, SI unit of frequency. 0.1Hz means "once per 10 seconds", 1Hz means "once per second", 10Hz means "10 times per second", and 192kHz means "192000 times per second".
In addition to a base sample rate, which represents the "normal" playing speed, SoLoud includes a "relative play speed" option. This simply changes the sample rate. However, if you replace your sounds with something that has a different "base" sample rate, using the relative play speed will retain the effect of playing the sound slower (and lower) or faster (and higher).
SoLoud lets you change the relative play speed of samples. Please note that asking for a higher relative play speed is always more expensive than a lower one.
Playing samples at higher or lower sample rate than they're intended can also cause resampling issues.
SoLoud has to perform resampling when mixing. In an ideal case, all of the sources and the destination sample rate are the same, and no resampling is needed, but this is often not true.
Currently, SoLoud supports "linear interpolation", which calculates linear interpolation of samples, as well as "point sample" resampling, which means it simply skips or repeats samples as needed.
Picking the resampler is done by editing the soloud.h file.
The linear interpolation resampler is used by default.
Higher quality resamplers are planned.
Where the sound is coming from in the stereo sound, ranging from left speaker only to right speaker only. SoLoud uses an algorithm to calculate the left/right channel volume so that the overall volume is retained across the field. You can also set the left/right volumes directly, if needed.
SoLoud uses throwaway handles to control sounds. The handle is an integer, and internally tracks the voice and sound id, as well as an "uniqueness" value.
If you try to use a handle after the sound it represents has stopped, the operation is quietly discarded (or if you're requesting information, some kind of generic value is returned, usually 0). You can also query the validity of a handle.
Audio latency generally means the time it takes from triggering a sound to the sound actually coming out of the speakers. The smaller the latency, the better.
Unfortunately, there's always some latency. The primary source of latency (that a programmer can have any control over) is the size of audio buffer. Generally speaking, the smaller the buffer, the lower the latency, but at the same time, the smaller the buffer, the more likely the system hits buffer underruns (ie, the play head marches on but there's no data ready to be played) and the sound breaks down horribly.
Assuming there's no other sources of latency (and there quite likely is), with 2048 sample buffer and 44100Hz playback, the latency is around 46 milliseconds, which is tolerable in most computer game use cases. A 100ms latency is already easily noticeable. In music terms, when playing drums, 40ms is too much, but when playing slowly evolving atmospheric pads, 200ms is fine.
Audio streams can also be modified on the fly for various effects. Typical uses are different environmental effects such as echoes or reverb, or low pass (bassy sound) / high pass (tinny sound) filters, but basically any kind of modification can be done; the primary limitations are processor power, imagination, and the developer's skill in digital signal processing.
SoLoud lets you hook several filters to a single audio stream, as well as to the global audio output. By default, you can use up to four filters, but this can be easily changed by editing SoLoud.h file and rebuilding the library.
SoLoud also support STFT filters, where the samples are converted to frequency domain for modification and back for playback.
In addition to mixing audio streams together at the "global" level, SoLoud includes mixing busses which let you mix together groups of audio streams. These serve several purposes.
The most typical use would be to let the user change the volume of different kinds of audio sources - music, sound effects, speech. In this case, you would have one mixing bus for each of these audio source groups, and simply change the volume on the mixing bus, instead of hunting down every sound separately.
When using environmental effects filters, you most likely won't want the background music to get filtered; the easiest way to handle this is to apply the filters to the mixing bus that plays the sound effects. This will also save on processing power, as you don't need to apply the environmental audio filters on every sound effect separately.
It's also possible that you have some very complex audio sources, such as racing cars. In this case it makes sense to place all the audio streams that play from one car into a mixing bus, and then adjust the panning (or, eventually, 3d position) of the mixing bus.
Additional feature of the mixing busses in SoLoud is that you can request visualization data from a bus, instead of just from the global scope.
SoLoud also contains a special kind of audio source called Queue. This can be used to queue other audio sources. Once one stops, the next one starts playing.
This can be useful when chaining sounds, like having a never ending song by queuing random patterns.
SoLoud can perform 3d audio calculations. If you do not need 3d (or "positional") audio, you can skip this chapter.
In practise, all the "3d audio" does is adjust panning and play speed of your audio sources, and as such can be seamlessly used with any "2d audio" that you may also have. This means that background music, for instance, does not need to be represented in the "3d world" in any way.
Any audio source can be 3d, including mixing busses. However, true 3d positioning only really makes sense for mono audio sources.
The doppler and attenuation calculations follow the OpenAL equations.
In order to use the 3d audio, use the 3d versions of the play commands, adjust the positions and velocities of your audio sources and listener with the set3dSource...() and set3dListener...() calls, and call update3dAudio() to ask SoLoud to recalculate the proper panning (and play speed, for doppler).
gSndHandle_orbit = gSoloud.play3d(gSfx_orbit, 50, 0, 0); // ... gSoloud.set3dSourceParameters(gSndHandle_orbit, orbitx, 0, orbitz, orbitxv, 0, orbitzv); // ... gSoloud.update3dAudio();
Sound sources may have a custom collider applied to them. This can be useful in many cases. For instance, if you have a river and want a water flow ambience to play when the player is near the water, you can either have a bunch of audio sources along the river (wasting a lot of voices) or you could have one audio source with a custom collider that checks if the player is near the river and adjusts volume accordingly.
Custom colliders are created by extending the AudioCollider class, which only has one function - collide. The function returns the calculated volume level. Once the custom collider class is made, you can set the collider to an audio source via set3dCollider() call. The call also takes an optional aUserData integer, which can be used to differentiate between the sounds. The same value is provided to the collide() call.
MyCustomCollider cc; gSound.set3dCollider(&cc); gSoloud.play(gSound);
The collide() call is made from update3dAudio() before directional panning is calculated, so it is possible to update the positions from inside your collide() function. That way you could figure out the general direction the sound should be coming from (thinking again of the river example), instead of just having a general volume fade.
Attenuation, or how audio volume decreases on distance, can be calculated in several ways. SoLoud supports three different modes (in addition to "no attenuation"): inverse distance, linear distance and exponential distance. These are calculated using the "clamped" models of OpenAL formulas.
All of the formulas take three parameters: rolloff factor, minimum and maximum distance. How these parameters affect the curves can be seen in the graphs below.
distance = CLAMP(distance, min_distance, max_distance) result = min_distance / (min_distance + rolloff_factor * (distance - min_distance))
The higher the rolloff factor, the more steeply the volume drops. At low enough rolloff factor, the volume never drops near zero. Values over 1 recommended (unless you have special needs). Values less than equal to zero result in undefined behavior.
Increasing the minimum distance pushes the start of the attenuation further. It also causes the curve to change. Note that the minimum distance must be above 0.
The maximum distance simply cuts the attenuation at the volume level it has reached at that point.
distance = CLAMP(distance, min_distance, max_distance) result = 1 - rolloff_factor * (distance - min_distance) / (max_distance - min_distance)
The rolloff factor for linear distance simply sets the maximum volume reduction. Using values outside the 0..1 range causes undefined behavior.
The minimum distance works as one might expect. Minimum distance must be less or equal to maximum distance.
The maximum distance works as one might expect. Minimum distance must be less or equal to maximum distance.
distance = CLAMP(distance, min_distance, max_distance) result = pow(distance / min_distance, -rolloff_factor)
The higher the rolloff factor, the more steeply the volume drops. At low enough rolloff factor, the volume never drops near zero. Values over 1 recommended (unless you have special needs). Values less than equal to zero result in really weird behavior.
Increasing the minimum distance pushes the start of the attenuation further. It also causes the curve to change. Note that the minimum distance must be above 0.
The maximum distance simply cuts the attenuation at the volume level it has reached at that point.
"Doppler effect" is the physical phenomenon that causes sound sources (like an ambulance) to sound higher-pitched when they're coming towards you and lower-pitched when going away.
A stationary sound (with a stationary listener) receives sound waves as you'd expect. When the sound source (or listener) are moving, the sound waves get "squashed" (for higher-pitch sound) or "stretched" (for lower-pitch sound) depending on whether the sound is approaching or receding from the listener.
SoLoud uses the OpenAL 1.1 formula for doppler calculation. The calculation depends on the listeners' and sound sources' velocities being properly calculated on the application's side. If you do not wish to use the doppler, simply leave all velocities at zero.
In addition to velocities, the doppler depends on the proper value of speed of sound. The default value is set at 343, which assumes that your world coordinates are in meters (where 1 unit is 1 meter), and that the environment is dry air at around 20 degrees Celsius. If those assumptions do not match your environment, change the speed with set3dSoundSpeed().
soloud.set3dSoundSpeed(1497); // we're in water
For a bit of artistic control, you can also set the doppler factor on a per-audio source basis to increase or decrease the strength of the effect. The default value is 1.0.
SoLoud can also delay the start of the effects by their distance. This uses the sound speed value and the distance between the listener and the sound source. Since this may be seen as a glitch as most games do not bother simulating this, it is disabled by default. To enable, use the set3dDistanceDelay() function on your sound sources.
Speakers are defined as 3d vectors, and the volume at which each speaker plays is calculated like:
volume = (dot(speaker_vector, sound_vector) + 1) / 2
In practise this ((dot+1)/2) calculation creates a field where sounds that come from the same direction as the speaker play at maximum volume, while sounds that come from exact opposite direction play at zero volume, and anything in between gets a reduced volume.