Music Queue Issues

Sup! I’m currently working on fixing up this Music queuing system GUI, But so far, it seems to be running into some issues, It plays music just fine since it’s all music from roblox, monstercat, etc

But the problem is that it just repeats the song, you have to manually skip it, and I haven’t been able to figure out how to change it :confused:

I’ve tried changing the queue around, and changing tables, etc, but i still can’t figure it out.

I haven’t bothered messing with the gui assets or their code because i don’t think that’s the problem.

local songs = {
	{ Name = "Relaxed Scene", Id = "rbxassetid://1848354536" },
	{ Name = "Stephen Walking - Glide", Id = "rbxassetid://7028957903" },
	{ Name = "Hyper Potions & Nokae - Expedition", Id = "rbxassetid://7023887630" },
	{ Name = "Sunset Chill (Bed Version)", Id = "rbxassetid://9046862941" },
	{ Name = "Pegboard Nerds & Tokyo Machine - Moshi", Id = "rbxassetid://7024340270" },
	{ Name = "Bensley - Vex", Id = "rbxassetid://7023635858" },
	{ Name = "Shingo Nakamura - Glow", Id = "rbxassetid://7028856935" },
	{ Name = "Glacier - Still", Id = "rbxassetid://7023771708" },
	{ Name = "Varien - The Language of Angels", Id = "rbxassetid://7029031068" },
	{ Name = "Case & Point - Descender", Id = "rbxassetid://7023650590" },
	{ Name = "Shingo Nakamura - Sapporo", Id = "rbxassetid://7028877251" },
	{ Name = "Grant - Color", Id = "rbxassetid://7023828725" },
	{ Name = "Protostar - New Horizons", Id = "rbxassetid://7028518546" },
	{ Name = "Nōpi - Endless Love", Id = "rbxassetid://7024245182" },
	{ Name = "Rameses B - Thinking About You", Id = "rbxassetid://7028540590" },
}

local icons = {
	Pause = "rbxassetid://6813750293",
	Play = "rbxassetid://6813750207",
	Mute = "rbxassetid://6813750387",
	Volume = "rbxassetid://6813750121",
}

local ORIGINAL_VOLUME = 0.35

local Player = {
	CurrentSong = songs[1],
	Queue = { table.unpack(songs) },
	Paused = false,
	Volume = ORIGINAL_VOLUME
}
table.remove(Player.Queue, 1)

local song = script:FindFirstChild("Sound") or script:WaitForChild("Sound")

local gui = script.Parent
local container = gui.Music.Container
local buttons = container.Buttons

buttons.Mute.MouseButton1Click:Connect(function()
	Player.Volume = Player.Volume == 0 and ORIGINAL_VOLUME or 0
	buttons.Mute.Icon.Image = Player.Volume == 0 and icons.Volume or icons.Mute
end)

buttons.Pause.MouseButton1Click:Connect(function()
	Player.Paused = not Player.Paused
	buttons.Pause.Icon.Image = Player.Paused and icons.Play or icons.Pause
end)

buttons.Previous.MouseButton1Click:Connect(function()
	table.insert(Player.Queue, 1, Player.Queue[#Player.Queue])
	song:Stop()
end)

buttons.Next.MouseButton1Click:Connect(function()
	song:Stop()
end)

game:GetService("RunService").Heartbeat:Connect(function()
	container.Bar.Indicator.Size = UDim2.new(
		math.clamp(song.TimePosition / song.TimeLength, 0, 1),
		0, 1, 0
	)
	container.Duration.Text = string.format("%i:%02i - %i:%02i",
		math.floor(song.TimePosition / 60), song.TimePosition % 60,
		math.floor(song.TimeLength / 60), song.TimeLength % 60
	)

	song.Playing = not Player.Paused
	song.Volume = Player.Volume
end)

while true do
	song.SoundId = Player.CurrentSong.Id
	container.SongName.Text = Player.CurrentSong.Name

	song:Play()
	song.Stopped:Wait()

	if Player.Queue[1] == Player.Queue[#Player.Queue] then
		table.insert(Player.Queue, 2, Player.CurrentSong)
		table.remove(Player.Queue, #Player.Queue)
	else
		Player.Queue[#Player.Queue + 1] = Player.CurrentSong
	end

	Player.CurrentSong = Player.Queue[1]
	table.remove(Player.Queue, 1)
end
1 Like

Could you send a place file with all objects referenced in the script so I could test it out?

I might be able to get a better idea of the issue if I can run it myself.

1 Like

Is the Looped property true for the Sound object?

Also, I noticed you used song.Stopped:Wait() instead of song.Ended:Wait(). I don’t know if you intended to, but the Stopped event only fires when the Sound is stopped due to Sound:Stop(), whereas the Ended event fires when the Sound playback has completed.

1 Like

Music Test Place.rbxl (54.5 KB)
Yeah Here’s The place file, if anything is out of place please let me know!

1 Like

Nope it’s not, just checked it, and Oh huh I didn’t catch that, ill check to see if it works

Edit: It did not work, i changed it to that and was not able to skip the second song at all, when i hit the skip button it just started the song over so that’s a no-go

1 Like

Here you go, this should fix the skip song problem.

buttons.Next.MouseButton1Click:Connect(function()
	song.TimePosition = song.TimeLength
end)

This will “end” the song making it so the loop will think that the song has finished and start a new one.

1 Like

This does fix the sound skip problem, allowing me to use song.Ended:Wait()
However the next song starts at the time length of the previous song, for instance, the 1st song is 1 minute, if i skip to the next song, then it will start the 2nd song at 1 minute in

1 Like

Ah, I think this should fix that problem:

while true do
	song.SoundId = Player.CurrentSong.Id
	container.SongName.Text = Player.CurrentSong.Name
	song.TimePosition = 0 -- Added to reset the song TimePosition 

	song:Play()
	song.Ended:Wait()

	if Player.Queue[1] == Player.Queue[#Player.Queue] then
		table.insert(Player.Queue, 2, Player.CurrentSong)
		table.remove(Player.Queue, #Player.Queue)
	else
		Player.Queue[#Player.Queue + 1] = Player.CurrentSong
	end

	Player.CurrentSong = Player.Queue[1]
	table.remove(Player.Queue, 1)
end

Sorry for the late reply, I had to wait though the whole song to check if it worked.

1 Like

The big issue here is this code is highly reliant on the Sound.Stopped Event, as seen here:

By interacting with any of the buttons that fire there functions the song stops but the song.Ended event does not fire. While your code fixes the song repeating problem, it breaks the ability to skip songs or go to a previous song.

The solution would require an function that waits for either the Sound.Stopped or Sound.Ended event to fire. I found a solution here

Fixing both problems, using @dwustpan’s code and the coroutine solution to the event problem, the final bit of code should look something like this

local function waitForEvent(...)

	local thread = assert(coroutine.running())
	local signals = {}

	local function resume()
		coroutine.resume(thread)
	end

	for _, event in pairs({...}) do
		table.insert(signals, event:Connect(resume))
	end

	coroutine.yield()

	for _, signal in pairs(signals) do
		signal:Disconnect()
	end

end

while true do
	song.SoundId = Player.CurrentSong.Id
	container.SongName.Text = Player.CurrentSong.Name
	song.TimePosition = 0 -- Added to reset the song TimePosition 

	song:Play()
	waitForEvent(song.Ended, song.Stopped)

	if Player.Queue[1] == Player.Queue[#Player.Queue] then
		table.insert(Player.Queue, 2, Player.CurrentSong)
		table.remove(Player.Queue, #Player.Queue)
	else
		Player.Queue[#Player.Queue + 1] = Player.CurrentSong
	end

	Player.CurrentSong = Player.Queue[1]
	table.remove(Player.Queue, 1)
end

I tested it, it works as intended.

4 Likes

Thanks for this! as well as @dwustpan and @Coderius For also contributing to this! i’ve been trying to fix this for so long, I really appreciate this! Thank you so much x 100 Lol

3 Likes

I like this solution, I just wanted to post an alternate one.

local BindableEvent = Instance.new("BindableEvent")

local function OnSongStateChanged()
	BindableEvent:Fire()
end

Sound.Ended:Connect(OnSongStateChanged)
Sound.Stopped:Connect(OnSongStateChanged)

while true do
	--Set sound's properties.
	--Play sound object.
	BindableEvent.Event:Wait() --Wait for the event to fire.
end
3 Likes