I’m not sure if there’s a solution to this. The solution I would have thought of is something you’re already using.
If you’re talking about my sonic-pi code, then yes. It doesn’t have to compensate for time, because sonic-pi’s sleep implementation is very accurate in time.
If you’re talking about the command-line code at the bottom, that simply plays the sample for a second, then stops, which can be run multiple times, which reveals the occasional clipping/general time inaccuracies.
The sound is cloned, then destroyed, to allow for it to play without having copies of the same sample spawn over and over, preventing any reading of its variables, though, I could try to see how it would work under that implementation.
I’d change the way it’s implemented and not delete the sound, while getting the current TimePosition of the sound to accurately tell where in the audio length it’s being emitted yk
I modified your piece of code and seems to sync up fine.
--!strict
local SoundService = game:GetService("SoundService")
local sound: Sound = script.Sound
local expectedInterval: number = 0.5
local lastTime: number = os.clock()
while true do
local currentTime: number = os.clock()
local elapsedTime: number = currentTime - lastTime
local waitTime: number = expectedInterval - elapsedTime
if waitTime > 0 then
local actualTime: number = task.wait(waitTime)
lastTime += actualTime
end
local sample = sound:Clone()
sample.Parent = SoundService
sample:Destroy()
end
Apparently, TimePosition doesn’t actually fire any events upon change.
I’ve tried your code, and the same issue takes place (I would’ve recorded the difference, but it sounds basically identical to what I recorded in the top post).
Maybe it’s an issue with the sound itself, though I’d doubt it. It seems fine; by itself it loops perfectly with Looped = true
.
I also probably should’ve linked the audio itself, so here it is:
you don’t need to get it every time it changes, all you need is to check the value once it’s playing to get the position the sound is at and use that to figure out when the next sound is supposed to start playing yk?
Always returns a fat zero.
local SoundService = game:GetService("SoundService")
local Samples = SoundService.Samples
local expectedInterval = 0.5
local lastTime = tick()
local function createSound()
local c = Samples.loop_mika:Clone()
c.Parent = Samples
c:Play()
local d = c.Changed:Connect(function()
print(c.TimePosition)
if c.TimePosition >= 1 then d:Disconnect() createSound() end
end)
end
createSound()
don’t do it in a .Changed connection, just do it in a loop or wait until the sound is loaded and playing and then get the TimePosition
I may be a bit off here but, from working with many languages there is a unwritten rule more or less not to call 0 time waits … wait(), wait(0) or the task.wait version. Roblox uses this in some templates so I assume your 0 time calls are not truly 0 time. If I need to go low, I will always use 0.33 or even 0.033. these are old assembler tricks on faking one FPS wait. The fact you are finding a 0 wait not consistent isn’t shocking. Many languages would just lock up with a call like that.
Edit: It would be interesting to see your test using this technique. I got a feeling it will pass with flying colors with a task.wait …
Like this? The wording was a little confusing.
Either way, the issue persists.
local SoundService = game:GetService("SoundService")
local Samples = SoundService.Samples
local offset
while true do
local c = Samples.loop_mika:Clone()
c.Parent = Samples
c:Play() -- doesnt seem to make a difference if its before or after
if not c.IsLoaded then c.Loaded:Wait() end
local nextOffset = c.TimePosition
print(nextOffset) -- still returns 0
if offset then c.TimePosition += offset end
task.wait(math.max(0.5 - nextOffset, 0))
offset = nextOffset
end
Removing the 0 waits doesn’t seem to change anything.
local SoundService = game:GetService("SoundService")
local Samples = SoundService.Samples
local expectedInterval = 0.5
local lastTime = tick()
while true do
local currentTime = tick()
local elapsedTime = currentTime - lastTime
lastTime = currentTime
local waitTime = expectedInterval - elapsedTime
lastElapsed = (waitTime > 0 and task.wait(waitTime) or 0.5)
local c = Samples.loop_mika:Clone()
c.Parent = SoundService
c:Destroy()
end
If you read the documentation, task.wait will wait until the heartbeat after the time is up. It also says that task.wait() will default to task.wait(0) and that it is equivalent to RunService.Heartbeat:Wait()
Yes. In the top post, I was asking for any possible alternatives to task.wait, or any way to mitigate its desync well enough, to where it doesn’t sound awful.
I didn’t say remove it. Anyways you’re using this to find an expectedInterval/elapsedTime. Why do that when you can just read the real position of the music being played.
I figured that is what it was doing. You call a real wait 0, you’re heading for a crash … lol
Because it is being destroyed in that code example.
Using an alternative version where it isn’t being destroyed, the result (unless I did it wrong) is also the same issue.
local SoundService = game:GetService("SoundService")
local Samples = SoundService.Samples
local offset
while true do
local c = Samples.loop_mika:Clone()
c.Name = "-"
c.Parent = Samples
c:Play()
if not c.IsLoaded then c.Loaded:Wait() end
local nextOffset = c.TimePosition
print(nextOffset)
if offset then c.TimePosition += offset end
local calc = 0.5 - nextOffset
if calc > 0 then task.wait(calc) end
offset = nextOffset
end
I was just pointing out, I could see how a wait(0) could be inconstant. There is no such a call … It’s like dividing by 0 … one of the things you just don’t do in a program or it crashes.
Going with your post … how does this work out?
local SoundService = game:GetService("SoundService")
local RunService = game:GetService("RunService")
local Samples = SoundService.Samples
local expectedInterval = 0.5
local lastTime = tick()
local function createSound()
local c = Samples.loop_mika:Clone()
c.Parent = Samples
c:Play()
lastTime = tick()
end
RunService.Heartbeat:Connect(function()
if tick() - lastTime >= expectedInterval then
createSound()
end
end)
createSound()