New sound API (easier to use, more versatile) and ability to set up sounds using CGE editor

Posted on

Example 3D game with spatial sounds - TCastleSound
Example 3D game with spatial sounds - TCastleSoundSource
Example audio player using LCL for UI and CGE for sound playing
Example cross-platform testing of sound playback using CGE UI
Example showing Doppler effect
Editor Sound options
Desining a collection of sounds

We have a new shiny API to play sounds in Castle Game Engine!

I think it’s a major improvement over the previous API (that revolved around TSoundBuffer and TSound classes). The new API is easier to use:

  • It hides some internal constraints (a limited internal number of sounds that can be mixed simultaneously, or impossibility to change internal buffer contents/streaming after loading). You don’t need to care about that anymore.

  • The lifetime of instances is easier to grasp. You control the lifetime of everything, and there’s no need to deal with TSound.OnRelease.

The new API is also perfect to visually set things up in the CGE editor. It uses behaviors for spatial sounds.

The new classes, that you should use now for all sound loading and playing, are:

  • TCastleSound: The most important class, you should use this always when you want to play any sound.

    This is a new non-visual component that represents a sound file with some playback parameters. The most important properties are:

    • URL — undoubtedly the most important property, set this to actually load the sound file.

    • Stream — optionally use “streaming”, which is an alternative loading method best suited for longer playing sounds (like music tracks).

    • Volume — how loud the sound is. This is multiplied by volume at TCastlePlayingSound.Volume and TCastleSoundSource.Volume and by spatial calculations.

    • 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 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, use TCastleSoundSource.Play for non-looping).

    TCastleSound also replaces previous TSoundType (TSoundType is now an alias of TCastleSound). So reading sounds from sounds.xml file and using SoundEngine.SoundFromName just gives you ready TCastleSound instance. This XML file now becomes a new way to define “a list of TCastleSound instances”. Though you can also now ditch the manually-crafted XML files, and use a new approach we mention below — design a non-visual collection of components like all_sounds.castle-component.

  • TCastleSoundSource: A way to play spatial (3D) sounds.

    This is a behavior (see previous post) that enhances any TCastleTransform so that it emits (possibly spatial) sounds.

    TCastleSoundSource refers to TCastleSound for an actual sound information. You can set TCastleSoundSource.Sound (for looping). Or call TCastleSoundSource.Play (for non-looping).

  • 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.

All CGE examples have been upgraded to use the new approach for sounds.

  • See all the examples in examples/audio subdirectory.

  • In particular I recommend opening the examples/audio/game_3d_sound demo. Aside from using new sound API, it has also been recently upgraded to use CGE editor and glTF intensively.

  • See also examples/fixed_camera_game for a new approach to design a collection of sounds (a new, better approach than manually crafting XML files). In particular:

    • examples/fixed_camera_game/data/sounds/all_sounds.castle-component describes all sounds
    • examples/fixed_camera_game/code/gamesound.pas loads them

Editor sound features:

  • Sound volume, and “auto-mute on play” are now available in the editor settings.

  • Drag-and-drop sound files on the viewport to automatically create a spatial sound: TCastleTransform, TCastleSoundSource, TCastleSound.

  • You can manage a collection of sounds independent of state/UI by simply using TCastleComponent as a design root and adding TCastleSound children. Save the resulting design to a file like all_sounds.castle-component. This is a great alternative to previous XML files to describe sounds which will soon be deprecated most likely.

    You can see an example of using the new approach in examples/fixed_camera_game mentioned above.

Distance model changes:

  • Our previous default SoundEngine.DistanceModel was poor (linear, which is not realistic).

    Now it is dmInverse, and corresponds to FMOD default and OpenAL default. It’s the most natural model to play 3D spatial sounds.

  • Our default MaxDistance was poor (1, equal ReferenceDistance, which means that there’s no attenuation with linear model at all).

    Now MaxDistance is 10000 by default (like FMOD). ReferenceDistance remains 1 by default (just like in OpenAL and FMOD).

  • Our possible TSoundDistanceModel were not portable (they reflected OpenAL models closely, and did not reflect FMOD models).

    We limit ourselves now to actually useful models, supported by various sound backends (OpenAL and FMOD) now: dmInverse and dmLinear.

Backward compatibility:

The sound API upgrade described here is almost completely backward-compatible. Old classes still work, just make a warning about deprecation at compilation. The breaking changes are:

  • By default we use dmInverse model now, as it is much more natural for 3D sounds (and it is default in both OpenAL and FMOD too, for the same reason). If you want the same approach as in previous engine version, set SoundEngine.DistanceModel := dmLinear. Remember to adjust the TCastleSound.MaxDistance to sound good.

  • Our sounds XML file no longer supports “random aliases”. See the bottom of upgrading wiki page for explanation. I suppose it was quite obscure feature, not used by many, and maintaining it is just too much cost in new API. If you miss this feature, I released a small unit that allows you to bring it back into your game: use and adjust this in your projects.

We also made a fix for sounds defined in X3D files: 3D sounds defined using X3D nodes are now correctly played in world coordinates, i.e. loading an X3D scene with sounds inside TCastleScene, and then transforming this TCastleScene makes a proper sound effect.

Our manual chapter about sound has also been updated to reflect the information above. It’s admittedly very brief now, quite similar to this news post, but I hope to extend it into more tutorial-like description soon.

Start the discussion at Castle Game Engine Forum