Playing simple sounds


How can I loop a sound (wave), stop playing it or start or stop playing from a certain point?
Sound1 has to loop, Sound2 only play once and then stop on a certain condition (not playing it to end).

I have this relevant code:

Sound1, Sound2: TCastleSound;

Sound1.URL:= ‘castle-data:/sounds/westbeach_sound.wav’;
Sound1.Volume:= 0.5;

Sound2.URL:= ‘castle-data:/sounds/boatstop.wav’;
Sound2.Volume:= 0.5;

// in cge editor
Sound1 := DesignedComponent (‘Sound1’) as TCastleSound;
Sound2 := DesignedComponent (‘Sound2’) as TCastleSound;

There is no Stop property so I did a Sound2.Volume := 0 but then the wave is still active and consuming memory.

The control the playback of sound, you need to use additional TCastlePlayingSound class, see brief note on Sound | Manual | Castle Game Engine . The instance of TCastlePlayingSound refers to TCastleSound. Like this:

Declare PlayingSound1:

  PlayingSound1: TCastlePlayingSound;

Play using PlayingSound1:

PlayingSound1 := TCastlePlayingSound.Create(...); // assign any owner, like FreeAtStop if inside the state, or just nil
PlayingSound1.Sound := Sound1;
PlayingSound1.Loop := true; // use this to make sound looping

So instead of SoundEngine.Play(Sound1) you now do SoundEngine.Play(PlayingSound1). And you get more control – you can play looping, you can stop at any time you want etc.

Now you can call whenever you want:


Note that there are other ways to control a looping sound:

  1. You can use SoundEngine.LoopingChannel, comfortable if this is a music track.

    To play, just do

    SoundEngine.LoopingChannel[0].Sound := Sound1;

    To stop, do

    SoundEngine.LoopingChannel[0].Sound := nil;
  2. You can also use TCastleSoundSource, which you can set up in the editor, and then do

    MySoundSource.Sound := Sound1;

    To stop, do

    MySoundSource.Sound := nil;

Thanks, this is all I need and it works. :grinning:
One more question: How can I fade out a sound? Should I put the PlayingSound.Volume in a loop or is there a more convenient way than something like this:

var VolumeValue: single;

while PlayingSound.Volume > 0 do
PlayingSound.Volume := VolumeValue - 0.05;

You can do it like

while PlayingSound.Volume > 0 do
   PlayingSound.Volume := PlayingSound.Volume - 0.05;

However, it’ll force the app to stop responding for some time. Therefore putting this in Update is the way to go:

procedure TMyUiState.Update(const SecondsPassed: Single);
  if (DoFadeOut) and (PlayingSound.Volume > 0) then
     PlayingSound.Volume := PlayingSound.Volume - 0.5 * SecondsPassed;
    DoFadeOut := false;

Or maybe better override TCastlePlayingSound and add Update, FadeIn and FadeOut routines, so that in TMyUiState.Update you won’t need to handle logic for all available sounds but only call SomeSound.Update;.

Note that if you would want to use the overridden component in the Castle Editor you’ll have to add it to custom components. See Custom Components | Manual | Castle Game Engine

Ok, thanks for replying!