Audio Keeps Changing Too Much?

So one of the scripts that I made is supposed to play an audio once, then move on to the next song in the list. The only problem is that the audio plays, waits less than a second, and moves on to the next song. A normal script–where each audio in the list is played–wouldn’t work for me because I eventually want a random song to be chosen, so I want to get this to work first.
Neither of the two end print statements appear in my output, which makes me think that the script is ignoring them? In other words, it just plays the next song without waiting for the first to end.


(this but 20+ more times)

This could also be because the scripts is loaded before the game finished loading (custom loading screen), but before I added the prints, it would only keep starting 6ish times. There’s also a lot of lag, but I’m not sure if the lag is causing the problem or if the problem is causing the lag (probably not because it also happens serverside).

--[[AUDIO CONVERSIONS
1 min = 60 seconds
2 min = 120 seconds
3 min = 180 seconds
]]
local sounds = {9047837288,1839784953,1838583566,1839784988,1839785182,1837478544,1837478738,1842365720,1839339414,1836362943,1840255453,108473305806813}
local s = script.Sound
local p
local r = 0
local function e()
	r +=1
	if r > #sounds then r = 1 end
end
game:GetService("RunService").Heartbeat:Connect(function()
	print("new")
	e()
	print(sounds[r])
	s.SoundId = "rbxassetid://"..sounds[r]
	s:Play()
	s.Ended:Wait()
	print("end")
end)
--I wanted to see if doing this would make a difference. It doesn't.
s.Ended:Connect(function()
	print("end2")
	print("new")
	e()
	print(sounds[r])
	s.SoundId = "rbxassetid://"..sounds[r]
	s:Play()
	s.Ended:Wait()
	print("end")
end)

It’s because you when you use s.Ended:Wait(), you’re only halting that specific function’s thread. When Heartbeat is fired in the next frame, it will run that function again. So essentially,

this line is doing nothing - you can’t pause the Heartbeat signal. You should use maybe something like

while true do
	print("new")
	e()
	print(sounds[r])
	s.SoundId = "rbxassetid://"..sounds[r]
	s:Play()
	s.Ended:Wait()
	print("end")
end

Now THIS will actually halt the loop until the song ends.

1 Like

Your Heartbeat connection is restarting the sound every frame, so the track never reaches Ended. That’s why you see many new prints and never hit your end prints. Also, calling Ended:Wait() inside an Ended:Connect handler is a logic error.

What’s happening

RunService.Heartbeat fires ~60 times/sec.
Each fire calls e() (advance index), sets a new SoundId, calls :Play(), then yields on s.Ended:Wait().
Next frame a new Heartbeat callback runs, advances again, sets a new SoundId, plays again. The previous sound is cut off before it can end, so Ended never fires and your end prints never run.
Your second block connects Ended but then immediately does Ended:Wait() again, which waits for the next end and can deadlock your flow.

local sounds = {
	9047837288,1839784953,1838583566,1839784988,1839785182,
	1837478544,1837478738,1842365720,1839339414,1836362943,
	1840255453,108473305806813
}

local s: Sound = script:WaitForChild("Sound")
s.Looped = false

local i = 0
local function nextIndexSequential()
	i = (i % #sounds) + 1
	return i
end

-- If you want random without immediate repeats, use this instead:
--[[
local last = 0
local function nextIndexRandom()
	if #sounds == 1 then return 1 end
	local pick
	repeat pick = math.random(1, #sounds) until pick ~= last
	last = pick
	return pick
end
]]

local function playIndex(idx: number)
	local id = sounds[idx]
	print("new", id)
	s.SoundId = "rbxassetid://"..id
	s.TimePosition = 0
	-- Optionally ensure it’s loaded:
	-- s.Loaded:Wait()
	s:Play()
end

local function playNext()
	local idx = nextIndexSequential()  -- or nextIndexRandom()
	playIndex(idx)
end

s.Ended:Connect(function()
	print("end")
	playNext()
end)

-- kick off the first track once
playNext()

1 Like