TCastleSound: The most important class, use this always when you want to play any sound.
TCastleSound
This is a non-visual component that represents a sound file with some playback parameters. The most important properties are:
TCastleSound.Url — set this to load the given sound file.
TCastleSound.Url
TCastleSound.Stream — optionally use "streaming", which is an alternative loading method best suited for longer playing sounds (like music tracks).
TCastleSound.Stream
TCastleSound.Volume — how loud the sound is. This is multiplied by volume at TCastlePlayingSound.Volume and TCastleSoundSource.Volume and by spatial calculations.
TCastleSound.Volume
TCastlePlayingSound.Volume
TCastleSoundSource.Volume
TCastleSound.Pitch — sound playing speed. As with volume, the volume of TCastleSound.Pitch is multiplied by similar parameters controlled at TCastlePlayingSound.Pitch and TCastleSoundSource.Pitch.
TCastleSound.Pitch
TCastlePlayingSound.Pitch
TCastleSoundSource.Pitch
TCastleSound by itself doesn’t manage playing the sound. You have to use SoundEngine.Play to play the sound (the simplest way to play, for non-spatial sounds) or TCastleSoundSource (for sounds that can be spatial; assign to TCastleSoundSource.Sound for looping, or use TCastleSoundSource.Play for non-looping.
SoundEngine.Play
TCastleSoundSource
TCastleSoundSource.Sound
TCastleSoundSource.Play
TCastleSoundSource: A way to play spatial (3D) sounds.
This is a behavior that enhances any TCastleTransform so that it emits (possibly spatial) sounds.
TCastleTransform
TCastleSoundSource refers to TCastleSound for an actual sound information. There are two ways to use it:
Set a looping sound in TCastleSoundSource.Sound. The sound source will play it automatically. Turn it on or off using TCastleSoundSource.SoundPlaying.
TCastleSoundSource.SoundPlaying
Play a sound calling TCastleSoundSource.Play. You can pass any TCastleSound or even your own TCastlePlayingSound to observe the playback.
TCastlePlayingSound
You can use both methods to play sounds. This way TCastleSoundSource can play multiple sounds at the same time.
TCastlePlayingSound: Optional, use if you need more control before and during the sound playback.
Both TCastleSoundSource and TCastleSound can be created, configured and linked in the CGE editor, e.g. when designing your state. You can hear the 3D sounds in the editor. You can also create and control them from code, as all CGE components.
See all the examples in examples/audio subdirectory.
In particular open the examples/audio/game_3d_sound demo. It’s a simple example of how TCastleSoundSource and TCastleSound can be set up in the CGE editor.
See also examples/platformer as a demo how to design a collection of sounds (see below for details).
Sound volume, and "Auto-mute on play" are available in the editor settings.
Drag-and-drop sound files on the viewport to automatically create a spatial sound: TCastleTransform, TCastleSoundSource, TCastleSound.
Load a sound file as TCastleSound like this:
Add CastleSoundEngine unit to your uses clause.
CastleSoundEngine
Declare variable to hold it like MySound: TCastleSound;
MySound: TCastleSound;
Initialize the variable and load sound file, e.g. in Application.OnInitialize:
Application.OnInitialize
MySound := TCastleSound.Create(Application); MySound.Url := 'castle-data:/my-sound.wav';
Play the sound like this:
SoundEngine.Play(MySound);
See source code of examples/audio/simplest_play_sound/simplest_play_sound.dpr for a working simplest possible example of this.
It is often comfortable to define a collection of sounds, which means that each sound file is assigned a simple name and configuration (e.g. priority, default volume), and all the sound files can be loaded easily from any place in code (regardless of the current view).
Do it by using a TCastleComponent as a design root and adding TCastleSound children. Save the resulting design to a file like sounds.castle-component.
TCastleComponent
sounds.castle-component
See also examples/platformer for an example of this approach. In particular, important files in this example are:
examples/platformer/data/sounds.castle-component describes all sounds. Edit this JSON file visually in CGE editor, just double-click on it in the CGE editor "Files" panel.
examples/platformer/code/gamesound.pas loads them. It defines a simple NamedSound routine used by the rest of code to play sounds like SoundEngine.Play(NamedSound('something')).
NamedSound
SoundEngine.Play(NamedSound('something'))
By default we use OpenAL to play sounds. It’s a great full-featured open-source audio library, perfect match for our open-source game engine.
You can alternatively switch to use the FMOD sound backend. This is just an option. FMOD is proprietary (not open-source) and commercial (though free in some cases, for indie developers).
Main advantage of FMOD in CGE for now is Nintendo Switch compatibility.
Big future advantage will be integration with the FMOD Studio. The goal of FMOD Studio is to make the work of sound designer easier. The sfx person can create sound effects in FMOD Studio, in a way that is agnostic to the game engine, and the code (like your game) simply sends "events" that may cause some sound effect (playing something, stopping something, fading in/out something…).
See also plans about FMOD Studio and Wwise.
Stereo sounds are never spatialized. It means that their 3D position relative to the listener doesn’t matter. If you want the sound to be spatialized, convert it to mono e.g. using Audacity.
There is a limit how many sounds are actually played. That is because mixing a lot of sounds at once is computationally expensive. Moreover, the human ear cannot distinguish a lot of sounds at once anyway.
The engine hides this from you, by managing sound sources using their TCastleSound.Priority. The most important sounds are played, the rest (when it goes over the limit) may be stopped as necessary. By default, the limit is 16 (TSoundAllocator.DefaultMaxAllocatedSources).
TCastleSound.Priority
TSoundAllocator.DefaultMaxAllocatedSources
To understand what actually happens, you can play with examples/audio/test_sound_source_allocator. The example has a limit of 6 (not 16), just to easier experience the problem. Load any sound (the longer the sound, the easier to be hit by the problem) and press "Play Sound" to see the slots being filled with playing sounds. When all the slots are filled, playing new sound necessarily means that some old sound has to be stopped.
The general advises to avoid stumbling on this problem:
Use TCastleSound.Priority to manage sound priority wisely.
Do not start many sounds, with longer duration, in a short amount of time. Make sounds shorter or make intervals between starting sounds longer or both.
E.g. let’s consider using TCastleTimer to start a sound. Let’s calculate whether this is going to cause us issues:
TCastleTimer
Assume the timer TCastleTimer.IntervalSeconds is 0.05, it means the timer fires 20 times per second.
TCastleTimer.IntervalSeconds
Assume that each timer event plays new sound, by a code like this:
procedure TViewMain.MyTimerEvent(Sender: TObject); begin SoundEngine.Play(Sound1); end;
Assume that the sound is long, e.g. 2 seconds.
This means that when 2 seconds end, the 1st sound is still playing, and 40 sounds are already started. You will likely experience issues, as the sound engine has actually rejected playing most of these sounds — only 16 are really mixed. Note that user probably couldn’t hear (at least, not clearly) 40 sounds at once anyway, even if we would mix them all.
The solution depends on the sound and use-case.
Maybe the sound has too long "tail" when it is almost-silent, playing echo, fading out etc. And maybe you can make it just shorter. E.g. cut the "tail" in Audacity. The screenshots below show a "brutal" cut done to make sound end shorter, to make it nicer you may want to fade out the sound at end.
Maybe you should just play the sound less often.
Maybe prepare a ready sound file that contains "premixed" sequence of shorter sounds. E.g. if you’re going to always play 10 sounds in succession, create one WAV file with all 10 sounds already mixed into one. In effect, you call SoundEngine.Play once, not 10 times. Both Castle Game Engine and the sound engine (like OpenAL) will have easier job to do.
To improve this documentation just edit this page and create a pull request to cge-www repository.