Playing simple sounds

Hi,

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;
SoundEngine.Play(Sound1);

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

// 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
SoundEngine.Play(PlayingSound1);

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:

PlayingSound.Stop;

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
begin
PlayingSound.Volume := VolumeValue - 0.05;
end;

You can do it like

while PlayingSound.Volume > 0 do
begin
   PlayingSound.Volume := PlayingSound.Volume - 0.05;
   Sleep(100);
end;

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);
begin
  inherited;
  if (DoFadeOut) and (PlayingSound.Volume > 0) then
     PlayingSound.Volume := PlayingSound.Volume - 0.5 * SecondsPassed;
  else
    DoFadeOut := false;
end;

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!
:smiley: