Audio
Audio plays sound clips on the machine's output device, several at once, driven by components on entities.
The concept
A game needs many sounds playing concurrently, each with its own volume and looping, without allocating while the game runs. Engines open one output device, keep a bounded pool of streams bound to it, and feed decoded clip data into those streams.
Decoded sound
Audio on a computer is a long run of numbers, samples, played at a fixed rate (for example 44,100 per second). A clip is decoded once into that raw form; playing it means copying samples to the device just ahead of the speaker. If the copying is late the sound crackles, which is why audio must never wait on slow work such as loading a file.
Mixing
Speakers receive one signal, so several sounds are mixed by adding their samples together, each scaled by its own volume (gain). Too many loud sounds at once can exceed the maximum and distort, so engines cap the number of simultaneous voices; a bounded pool also keeps memory use predictable.
Sound as game state
Treating a sound as something an entity has (play, stop, loop) rather than a one-off call means it can be saved in a scene, edited in a tool and driven by the same systems as everything else. The system, not gameplay code, owns the details of starting and stopping streams.
How ASGE does it
AudioDevice and AudioStream
asge::audio::AudioDevice owns SDL's audio subsystem, one physical playback device and a fixed pool
of 32 AudioStreams. Initialize() opens the default device;
CreateStream(AudioClip&) returns a std::shared_ptr<AudioStream> matching the clip's
format, and DetachStream() gives the slot back. SetGain() sets the device volume. An
AudioStream wraps one SDL_AudioStream: PutData() queues a clip,
ClearData() empties it, SetAudioGain() sets its own volume. The shared pointer stays valid
even if another detach relocates its slot.
Application initializes the device alongside the video system and passes it into your game.
AudioSource and AudioSystem
Gameplay does not touch streams. An entity gets an AudioSource component (clip path, volume, loop),
and you use PlayAudioSource, StopAudioSource and DetachAudioSource to change
its state. AudioSystem, the last system in Game::Update's fixed order (see
Game loop & timing), starts newly playing sources, restarts looping ones whose queued audio ran out, stops finished
non-looping ones, and clears the data of stopped ones. A source keeps the same stream for its whole lifetime, so replaying
it never creates a new one. Clips are loaded through the
asset manager as media::AudioClip.
using namespace asge::game::components;
auto source = registry.GetComponent<AudioSource>( entity ); // Result<reference_wrapper<AudioSource>>
if ( source )
{
PlayAudioSource( source.Value().get(), /* inLoop */ true ); // AudioSystem picks it up this frame
// StopAudioSource( ... ) stops it; DetachAudioSource( device, ... ) frees its pool slot
}
See also
Source: Audio/AudioDevice.hpp, Game/Components/AudioSource.hpp, Game/Systems/AudioSystem.hpp.
Audio demo