Music Player With Progress Bar

Hello, I want to create a music player with a progress bar that shows how far through the song is. I’ve got the script that randomises the songs but I don’t know how I would make a progress bar. This my server script in Workspace.

local songs = script.Parent
local tablee = {}
local lastsong = nil
 
for i,v in pairs(songs:GetChildren()) do
    if v:IsA("Sound") then
        table.insert(tablee,v)
    end
end
 
while true do
    for a,c in pairs(tablee) do
        local chosensong = tablee[math.random(1,#tablee)]
        repeat wait() chosensong = tablee[math.random(1,#tablee)] until chosensong ~= lastsong
        lastsong = chosensong
        chosensong:Play()
        chosensong.Ended:Wait()
        chosensong:Stop()
    end
    wait()
end
1 Like

You have to work with the Sound TimeLength and TimePosition like this:

ProgressBar.Size = UDim2.new(chosensong.TimePosition / chosensong.TimeLength, 0, 1, 0)

I don’t know if this script would work because It’s just an example but you have to do it somehow like this.

I’ve already tried something like this but it doesn’t work.

Use RunService for the script.

game["Run Service"]:BindToRenderStep("", 100, function()
	ProgressBar.Size = UDim2.new(chosensong.TimePosition / chosensong.TimeLength, 0, 1, 0)
end)

Something like this.

Where would I put the script, because right now it’s a server-sided script in Workspace.

Hey, I put this together. It will work on the Server and the Client. It returns the percentage completion of the Sound. the percentage is to the nearest tenth. Hope this helps!

local Sound = script.Parent.Sound



for i = 1, math.huge do
	local SoundLength = Sound.TimeLength
	local CurrentPos = Sound.TimePosition
	local Percentage = CurrentPos / SoundLength * 100
	local Clip = math.floor(Percentage / 0.1) * 0.1
	print(Clip)
	wait()
end

Here’s what I would do:

  • Handle the progress bar locally (As in use Gui Objects/Frames)

  • Create a ScreenGui inside StarterGui, insert 2 Frame Objects inside (1 for overlaying the background, 1 for getting the progress bar)

  • Get the progress-bar of the Frame by dividing the Sound.TimePosition / Sound.TimeLength

    • You can either use Size or TweenSize, I suppose Size would be more efficient
  • Use the RunService’s RenderStepped Event to detect changes every frame or so on the client

You should have something like this in a LocalScript inside 1 of the local descendants:

local RunService = game:GetService("RunService")
local Player = game.Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local MusicProgress = PlayerGui:WaitForChild("ProgressBar")
local SongTable = {}
local Songs = workspace.Songs

for _, Song in pairs(Songs:GetChildren()) do
    if Song:IsA("Sound") then
    table.insert(SongTable, Song)
end

RunService.RenderStepped:Connect(function()
    local RandomSong = SongTable[math.random(1, #SongTable)]

    if RandomSong and RandomSong.IsPlaying == true then
        local Progress = RandomSong.TimePosition / RandomSong.TimeLength
        MusicProgress.ProgressBar.Size = UDim2.new(Progress, 0, 1, 0)
    end
end)
1 Like

Where should I put the local script?

  • StarterPlayerScripts
  • StarterPack
  • StarterGui

Any of those would work, just be sure to parent your objects in the correct way in relation to the variables I mentioned

I’ve put this

local RunService = game:GetService("RunService")
local Player = game.Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local MusicProgress = PlayerGui.MusicGui.Frame
local SongTable = {}
local Songs = game.Workspace.Sounds

for _, Song in pairs(Songs:GetChildren()) do
	if Song:IsA("Sound") then
		table.insert(SongTable, Song)
	end

	RunService.RenderStepped:Connect(function()
		local RandomSong = SongTable[math.random(1, #SongTable)]

		if RandomSong and RandomSong.IsPlaying == true then
			local Progress = RandomSong.TimePosition / RandomSong.TimeLength
			MusicProgress.ProgressBar.Size = UDim2.new(Progress, 0, 1, 0)
		end
	end)
end

inside a local script inside the progress bar but it isn’t working or even playing the songs.

Did I really just put the RandomSong variable inside the RenderStepped event-

The reason why it’s not playing the songs is cause it’s only listening to what’s being played on the server side, you should probably just create a random song picker check so it plays a random song:

local Songs = game.Workspace.Sounds:GetChildren()

while true do
    local RandomSong = Songs[math.random(1, #Songs)]

    if RandomSong:IsA("Sound") then
        RandomSong:Play()
        RandomSong.Ended:Wait()
        RandomSong:Stop()
    end
end

Also this should be the fixed script for the local side:

local RunService = game:GetService("RunService")
local Player = game.Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")
local MusicProgress = PlayerGui.MusicGui.Frame
local Songs = game.Workspace.Sounds

RunService.RenderStepped:Connect(function()
    for _, Song in pairs(Songs:GetChildren()) do
	    if Song:IsA("Sound") and Song.IsPlaying == true then
        	local Progress = Song.TimePosition / Song.TimeLength
    		MusicProgress.ProgressBar.Size = UDim2.new(Progress, 0, 1, 0)
    	end
    end
end)
2 Likes

Once last quick question, the progress bar goes past the frame is there any way I can change that?

Your progress bar should be parented inside your OverlayFrame, and it should do the trick

Your OverlayFrame should be something like this: (0.5, 0, 0.2, 0)

1 Like

Now it only plays once, stops playing any songs, and says an error at the end of the first song that says Play is not a valid member of Script “Workspace.Sounds.SoundManager”.

Okay I edited the script in relevance to the server, could you try it again?

1 Like

Hey so I’m using this system and I’m a little confused with the progress bar, it goes past the overlay frame.

This is what I want it to look like when it’s full
image

Overlay size: {0.394, 0},{0.176, 0}

The progress script:
local RunService = game:GetService(“RunService”)
local Player = game.Players.LocalPlayer
local PlayerGui = Player:WaitForChild(“PlayerGui”)
local MusicProgress = PlayerGui.music.Background
local Songs = game.Workspace.Sounds

RunService.RenderStepped:Connect(function()
	for _, Song in pairs(Songs:GetChildren()) do
		if Song:IsA("Sound") and Song.IsPlaying == true then
			MusicProgress.Parent.SongName.Text = Song.Name
			local Progress = Song.TimePosition / Song.TimeLength
			MusicProgress.progress.Size = UDim2.new(Progress, 0.150, 0.08, 0)
		end
	end
end)

image