Script plays only 1 audio when 2 should be played

local songs = script.Parent

while wait() do
	for i, song in pairs(songs:GetChildren()) do
		if song:IsA("Sound") then
			local randomNo = math.random(1, #songs:GetChildren())
			local randomSong = songs:GetChildren()[randomNo]
			local randomSongMuffled = songs:FindFirstChild(randomSong.Name.."Reverb")
			randomSong:Play()
			randomSongMuffled:Play()
			randomSong.Ended:Wait()
			randomSongMuffled.Ended:Wait()
		end
	end
end

Hi all, this is a script I have in which I want “randomSong” and “randomSongMuffled” to be played at the same time, however this doesn’t seem to work properly, only “randomSongMuffled” plays and “randomSong” does not. I don’t really script so I would appreciate if someone could help me with this.

3 Likes

i’m wondering how it doesn’t break when it picks a reverb song or the script itself as the random song

This doesnt guarentee a Sound is chosen as randomSong as it is just a random child of Songs

I can’t exactly tell, but it seems like the culprit here is poor structuring of data. You’re mixing muffled tracks with normal tracks and mixing Sounds and other Instance types into one place. This can cause you to play a muffled track twice, or cause an error as your code might try to run Play on a Script.

First, I’d suggest making each normal Sound (not the Reverb types) a child of the script. This makes sorting it easier as you’ll ensure every child of the script is a Sound, and you won’t have a script mixed in with them.

Next, make each “Reverb” sound a child of the normal sound. Instead of having the normal and Reverb versions all in one place, simply have a hierarchy like script.SoundName.Reverb where Reverb is the “muffled” version of the song.

Now, since you know every child of script is a sound and that every child of script should have a child named Reverb (or whatever you want), you have a much more straightforward solution.

while true do -- Don't do wait/task.wait here... just don't v_v
	local songs = script:GetChildren() -- We can store this as a variable for efficiency
	local randomNo = math.random(1, #songs)
	local randomSong = songs[randomNo]
	local randomSongMuffled = randomSong.Reverb -- If you're not sure that `Reverb` will exist, use FindFirstChild and nil check it
	randomSong:Play()
	randomSongMuffled:Play()
	randomSong.Ended:Wait()
	randomSongMuffled:Stop() -- You could cause an infinite wait here if randomSongMuffled is already ended.
	-- I choose to just stop it outright, but you could check if you really want to:
		-- if randomSongMuffled.IsPlaying then randomSongMuffled.Ended:Wait() end
		-- I don't think this is necessary, though.
	-- An explicit wait is not necessary here. `randomSong.Ended:Wait()` already does this for us.
end

Finally, make sure none of your Sound instances have Looped set to true, or that will cause obvious problems.

--a function for fetching all current songs
local function getSongs(): {Sound}
	local songs = {}
	for _, v in pairs(script.Parent:GetChildren()) do
		if v:IsA("Sound") then table.insert(songs, v) end
	end
	return songs 
end

--a function that fetches the muffled song given the normal one
--I added the error because I suspect you used ChatGPT and "Reverb" was a hallucination
local function getMuffledSong(songs: {Sound}, songName: string): Sound
	local song = script.Parent:FindFirstChild(songName.."Reverb") 
	if not song then
		error(songName.." with reverb doesn't exist, create it!")
	end
	return song 
end

--a function that combines both signals into one through a proxy event
--this assumes that both songs will end at some point (no pauses etc)
local function waitForSongsToFinish(song1: Sound, song2: Sound): ()
	local proxy = Instance.new("BindableEvent")
	local finished1 = false
	local finished2 = false
	song1.Ended:Once(function()
		finished1 = true
		if finished2 then proxy:Fire() end
	end)
	song2.Ended:Once(function()
		finished2 = true
		if finished1 then proxy:Fire() end
	end)
	proxy.Event:Wait() 
	proxy:Destroy()
end

while true do
	--dynamically fetch songs on each iteration
	local songs = getSongs()
	--pick a song fully randomly
	local song = songs[math.random(1, #songs)]
	--from the song name, get the muffled song
	local muffledSong = getMuffledSong(song.Name)
	--play both songs
	song:Play()
	muffledSong:Play() 
	--wait for both songs to finish
	waitForSongsToFinish(song, muffledSong)
end

Something I was working on from time to time. Your question sparked me to look at it again.
This project address any issues you may be having..

ClientMusicPlayer – open source