Music Randomizer Issues

I’ve seen a bunch of resources for this online, but what I want is different. Most resources just play a random music ID, and some will randomly play everything without repeating.

The randomizer I’m making does two things: It plays all of the music before starting over, and when it starts over the last song played on the old shuffle won’t be the first song played on the new shuffle, ie:
First random shuffle: 2, 1, 3
Second random shuffle: 3, 1, 2 ← This is not okay because 3 had just played

Here’s the script, it is random, but sometimes plays repeats which means the part about the previous song is broken.

local Songs = {
	"rbxassetid://5869422451",
	"rbxassetid://3060494212",
	"rbxassetid://17755696142"
}
local AlreadyPlayed = {}
local Sound = script.Parent.Sound

local PreviousSong
while wait() do
	if #AlreadyPlayed == #Songs then
		table.clear(AlreadyPlayed)
	end
	
	local RandomID = Songs[math.random(1,#Songs)]
	if table.find(AlreadyPlayed, RandomID) then
		repeat
			wait()
			RandomID = Songs[math.random(1,#Songs)]
		until
		print("found")
	else
		if tostring(RandomID == PreviousSong) then repeat wait() RandomID = Songs[math.random(1,#Songs)] until tostring(RandomID ~= PreviousSong)
			Sound.SoundId = RandomID
			Sound:Play()
			Sound.Ended:Wait()
			PreviousSong = RandomID
		end
	end
end

On a side question, instead of doing this to make a table, can I just locate a folder with the song instances inside and rip the song ID’s from there?

local Songs = {
	"rbxassetid://5869422451",
	"rbxassetid://3060494212",
	"rbxassetid://17755696142"
}
1 Like
local Sound = script.Parent.Sound;

local Songs = {
	"rbxassetid://5869422451",
	"rbxassetid://3060494212",
	"rbxassetid://17755696142"
};

local function Shuffle(t)
	local s = {};
	for i = 1, #t do
		s[i] = t[i];
	end
	for i = #t, 2, -1 do
		local j = math.random(i);
		s[i], s[j] = s[j], s[i];
	end
	return s;
end

local lastSong = Songs[1];
local Queue;

while wait() do
	repeat
		Queue = Shuffle(Songs);
	until Queue[1] ~= lastSong;
	lastSong = Queue[#Queue];

	for _,SongID in ipairs(Queue) do
		Sound.SoundId = SongID;
		Sound:Play();
		Sound.Ended:Wait();
	end
end

Something like this?

  • See @doctorpepper126’s response for how to pull the IDs from a folder of Instances
2 Likes

Unrelated… but this part of this script is repeating until the print function. It will only iterate once, is this intentional?

And for this, just do

local Songs = {};
for i, e in SongFolder:children() do
   if e:IsA('Sound') then
      table.insert(Songs, e.SoundId);
   end;
end;
2 Likes

Alright so I rewrote the script.

local RANDOM_OBJECT = Random.new()

local songs = {}
local alreadyPlayed = {}
local prevSong
local folder = script.Songs
local sound = script.Parent.Sound

for _, sound: Sound in pairs(folder:GetChildren()) do
	table.insert(songs, sound.SoundId)
end

while (true) do
	while (#songs > 0) do
		local randomSong
		repeat
			randomSong = songs[RANDOM_OBJECT:NextInteger(1, #songs)]
		until (randomSong ~= prevSong)
		table.insert(alreadyPlayed, randomSong)
		table.remove(songs, table.find(songs, randomSong))
		prevSong = randomSong
		
		sound.SoundId = randomSong
		if (not sound.IsLoaded) then
			sound.Loaded:Wait()
		end
		sound:Play()
		sound.Ended:Wait()
	end
	
	songs = table.clone(alreadyPlayed)
	table.clear(alreadyPlayed)
end

So, this assumes you’ve got a folder inside of the script called Songs with Sound objects in it. It’ll take all SoundIds of those sounds and place them into a table, as you wanted. It’ll also ensure that the last song in a shuffle is not played first in the very next shuffle. If you want a more thorough explanation as to what’s going on here, don’t hesitate to ask!

A couple of side notes, though.

The Random object is newer and you shouldn’t use math.random. I don’t know whether Roblox plans to deprecate math.random(meaning they’d no longer support it if it were to stop working), but they tend to do that to features that get a newer counterpart. It has more functionality than math.random and you should get into the habit of using it. Here’s the documentation page for it.

You also should not use wait(), as it’s deprecated, and you instead should be using task.wait().

1 Like

As far as I can tell this works perfectly, I don’t detect any repeats but this code is hard to interpret so I’m not 100% sure. Thank you!

Yeah I just needed a placeholder some other unrelated code was there…

Thank you, I had made the assumption that I could just do :GetChildren() inside a table or something because I swore I had done that before…

Thank you this also works fantastic

Interesting, I did not know about the random object, but I knew about task.wait() and old habits die hard :sad:

Anyway thanks to all three of you for reaching out!

No worries. I’ll try to give a brief explanation:

  • The Shuffle function is (I believe) a variant of the Fisher-Yates shuffle.

  • I’ve used lastSong as a variable to define the last song that played in each queue. I’ve assigned it to Songs[1] for the first iteration (just so it’s not empty), but every time a new Queue is made it replaces this with the last song in that Queue: lastSong = Queue[#Queue]

  • On each iteration, it will shuffle the song list over-and-over again until the first song in the Queue (Queue[1]) is not the same as lastSong. At which point the repeat ... until ... breaks.

  • Then the for _,SongID is just looping through the Queue in order to play each song.

1 Like