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:
-
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;
-
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.
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