How can I loop a section of a sound?

Like the title says, how can I loop a certain section of a sound without relying on split audio samples for the intro and the loop portions for the music using Python? Would save a lot of time and memory too.

KX_SoundActuator.time, easily enough.

This one is cursed, however. Setting it to zero may set it to -48k instead and crash your sound drivers by some miracle of shoddy engineering. Trying to loop backwards will be weird, trying to be smart and mess with the playback speed this way will also not work as you might expect.

First issue: never going to be fixed. For the second one there might be a way, and as for the third one to change playback speed you want to look at pitch instead.

Here is a barebones example:

from bge.logic import getCurrentController;
cont=getCurrentController();
own=cont.owner;

sound=cont.actuators["Sound"];
if("nit" not in own):
    sound.startSound();
    own["nit"]=1;

def loop(x, start, end):
    if(x.time>end):
        x.time=start;
    
    elif(x.time<start):
        x.time=start;

loop(sound, 0.01, 3.25);

And here’s calling that script with them blocks.

As a final note, notice the delay sensor is only checking every 16 frames or so, you might think that’s too slow of an update but it might as well be overkill. Since the value is in seconds you only need to check however many fractions of a second (in logic frames) you’re interested in slicing.

ADDENDUM (07/03/23):

Activation of the sound actuator through a controller pulse is required for 3D sound to take the camera into account; the original script does not handle this.

Adding cont.activate(sound) or it’s brick equivalent always->and->sound ensures that the camera update is run, fixing the issue.

There’s another problem that I’ve come across, but not due to sound looping. I’ve made an old fountain, and instructed the droplets object to play a sound file. But when played with 3D sound, it will never fade away no matter the distance I place the view at. Using the actuator normally makes 3D sound work.

It works on all other objects using the script. The sound is set on Loop Stop, and there is an Always Sensor set to True Pulse mode (0) tick interval.

It would seem you need to call cont.activate(sound) once every frame to get 3D sound; equivalent to always->and->sound.

Wait, how did I think of that? Funny story.

First thought I had: could writes or reads to time affect 3D sound settings?

Probably not. You can see it def’d here, it’s just wraps over getset. I’m not seeing anything wrong besides the formatting.

If it’s the AUD_Handle setters themselves, I didn’t check. But I don’t think 3D settings would be sufficiently related to time that the setter for one would mess with the other.

So I eliminated that possibility. The only other thing left was the call to startSound, which is wraps over play. And what do you know, that’s where the 3D settings get initialized.

So, I thought I had a pretty good theory: there must be some further bit of initialization that play by itself does not execute. But I was wrong. What really happens is play by itself does not invoke Update, and so this bit never runs, and so the camera is never taken into account.

Thus, I conclude: you have to activate a sound actuator every frame to get 3D sound.

Now, one suspicion I have is that I skipped the activation because it made something else stop working, but Blender doesn’t work on my computer anymore so I can’t check any of this. Try it out and see what happens.

Cheers.

1 Like

It worked! 3D sound now works when enabled along with the looping!

Nice c:

I’ll update the original response to include a note for this, in case someone stumbles into the same issue in the future.