As a Roblox developer, it is currently too hard to create loop points for sounds. Although Roblox does have looping, it’s extremely limited and does not recognize the loop points in an audio file or allow developers to set them.
What are loop points?
We all know what a sound loop is, once the end of the sound is reached, it’s replayed. Pretty simple.
But this type of looping doesn’t always work. What if we want an intro to our sound? Or what if we want an outro after X loops or another condition?
This is where loop points come in! Loop points allow us to define when a loop “begins” and a loop “ends”, excluding those parts from the loop!
The sound starts with the intro, and once it reaches the end of the loop, it goes back to the start of the loop, eventually being able to end with the outro, all completely seamlessly. This is extremely useful for certain sound effects and background music, allowing developers to get more creative with their sound design and composing.
How are they stored?
In reality, there’s no “real” standard to storing the loop points, even within the same format. In the file formats Roblox allows…
-
.wav
has no standard as far I can tell, it’s typically used for short sounds that rarely loop or storing raw sound data for later processing. -
.mp3
also has no standard as far as I can tell, as encoders tend to introduce a silent padding in the sound, making these calculations too imprecise. See this topic for more details. -
.ogg
, which is the most common filetype used in games and other software, doesn’t have a standard in its specs either, however, my research suggests that a de facto standard exists across game engines.
It appears that game engines typically get the loop data from the file’s metadata tags. There’s two common variations of this practice:-
LOOPSTART
andLOOPEND
tags:LOOPSTART
indicates in which sample the loop starts,LOOPEND
indicates in which sample the loop ends.
-
LOOPSTART
andLOOPLENGTH
tags:LOOPSTART
still indicates in which sample the loop starts, butLOOPLENGTH
indicates the length of the loop in samples.
Additionally, some engines prefer to leave an exposed API for developers to set LoopPoints, but usually still allow developers to read sound file metadata, keeping the practice of storing the points in metadata like this common.
-
Examples of ogg metadata or engine APIs being used for loop points: Ogg LOOPSTART | Forum, Looping OGG Files for use in RPG Maker & Others :: rpgmaker.net, seamless looping for ogg supported? — dengine Forums, Audio loop - The Doom Wiki at DoomWiki.org, BGM loop points, How To: Looping music files - Moondust Wiki, Looping a Sound - Valve Developer Community, https://forum.unity.com/threads/defining-loop-points.675580/.
The problem
Sadly, Roblox doesn’t recognize those metadata tags in an .ogg
file nor does it allow us to set loop points in-engine, meaning that looping always spans the whole sound.
Edit: After some testing, I’ve discovered that the workaround below isn’t practical. Roblox’s API simply doesn’t provide timings precise enough to make a seamless transition.
The only way to get around this is to:
- Not use Roblox’s native looping and instead store the start and ending position of the loop somewhere (whether that is in attributes or inside of a script).
- Add a buffer after the ending point that is exactly equal to the first few seconds of the loop segment
- Every frame, check if the sound’s
TimePosition
is equal or above to the loop end point, then subtract the Current TimePosition by the loop’s lengthTimePosition -= (LoopEnding - LoopStart)
.
The “buffer” is necessary because Lua simply can’t run fast enough to detect the loop ending being reached before playback goes past it (this is only possible by the engine responsible for playback!), not including it would result in a noticeable silence (or the sound’s outro) being heard before the sound looped. This method also demands more manual work, as you’d have to hardcode your time positions in your code or datamodel instead of just configuring it while exporting the sound.
Sadly, as you have to include a buffer, certain outros that play shortly after the loop simply aren’t possible, as they would interfere with it.
Edit: After some testing, I’ve discovered that the workaround below isn’t practical. Roblox’s API simply doesn’t provide timings precise enough to make a seamless transition.
You can also try splitting the sound into an intro and a loop, but this would still require a buffer for the intro sound and would force developers to upload two sounds, impacting their limited sound upload quota. It’s actually a worse solution!
Roblox should standardize and check for sound metadata tags that determine how a looped sound should be played. Alternatively, Roblox could give us access to the sounds’ metadata tags in-engine and allow us to set the loop points in-engine (ex: Sound.LoopStart
, Sound.LoopEnd
), essentially having the same effect but making the developer responsible for picking the format in which they store the data in. Roblox should follow the precedents set by existing engines.
If Roblox is able to address this issue, it would improve my development experience because creating loop points for sound would not require hacky workarounds and hardcoding that doesn’t fit all usecases. that doesn’t work at all. Outros would be possible, no superfluous audio uploads would be needed and sound effects and background music with a beginning, middle and ending would be more feasible and easier to implement. It’d also allow for better integration with sound editing software (Audacity, FL Studio, Reaper, etc…), as they already include easy ways of inserting these fields into the metadata.
FMOD’s API (the audio engine Roblox uses) already has a method for setting the loop points of a sound, so it really make no sense that this functionality is missing.