Music Player Tutorial

A couple of months ago, I made a community tutorial regarding the same topic of how to make a server-sided music queuing system. That tutorial, I believe, is to be considered outdated and unworking. In this tutorial, I will teach you how to make the base music player system and the ability to easily implement client-side features yourself to manage the music player system.

This is meant to be an updated version of my previous tutorial. I suggest having a basic understanding of how remote events work before following this tutorial, and as well as reading the developer documentation on the sound object.

Step 1:
We will first need to create our remote events, which will be used to communicate from the client-side GUI to the server. Please keep in mind that I will not teach you how to make the GUI, nor how to script it on the client. As I aforementioned, it is recommended to have a basic understanding of how remote events work.
image

Remote Event Definitions:
GetPlayingSong - Used to get the name of the current song that is playing.
NewSong - Will be fired upon all clients when a new song starts playing. (Params: songName)
RefreshQueue Will be fired upon all clients when a new song gets requested/starts playing, to refresh the music queue GUI on the client. (Params: queueTable)
RequestSong Will be fired from the client to request a song included in the music player. (Params: songID)

Step 2:
We will create the script in ServerScriptService which will handle the music player system.
image

Step 3:
We will now begin coding our music player. :grinning: We will first declare our required variables, and then we will move on to the system code.

local rep = game:GetService("ReplicatedStorage") -- The ReplicatedStorage service.
local events = rep.MusicPlayerEvents -- This variable is the folder in which the remote events/functions are stored in.

local queue = {} -- This table is where we will store/remove requested songs.
local songs = {} -- This table is where all the songs will be stored.

local currentSong = "No song playing"

local sound = Instance.new("Sound") -- We create a new Sound instance that will be used to play the music.
sound.Name = "MusicPlayerSound" -- We set the name of the new sound instance to "MusicPlayerSound"
sound.Parent = workspace -- We parent the sound to the workspace.

The structure of a song added to the songs table should be like this:

{
    Name = "Song - Name", -- The name of the song.
    ID = 0000000000 -- The asset ID of the song.
    Pitch = 1 -- The pitch of this audio. (Default is 1)
}

We now need to connect the remote events and functions to a function.

events.GetPlayingSong.OnServerInvoke = function()
	return currentSong -- When the GetPlayingSong remote function gets invoked, we will return the currently playing song name back to the client who invoked it.
end

events.RequestSong.OnServerEvent:Connect(function(player, id)
	local song -- We create our "song" variable and will later be properly declared by the for loop, if it finds the song the player is trying to request.
	
	for _, s in ipairs(songs) do
		if s.ID == id then
			song = s
		end
	end -- For every song we have stored in the songs table, we will check if its ID index is equivalent to the ID the player is trying to request. If so, we declare the song variable as that song.
	
	if song then
		table.insert(queue, song)
		events.RefreshQueue:FireAllClients(queue)		
	end -- If the song was found, we will insert it into the requested queue table. We will also fire the RefreshQueue remote event upon all clients.
end)

The request song code can be modified, of course. If you want to have a system where the player needs to pay robux to request a song, then you can copy the code above and move it into a ProcessReceipt function.

We will now begin coding the base music player system. It is actually shorter than you think and very efficient I would say. :wink: (Please be sure the while loop code is at the very bottom of the script.)

while true do
	if #songs > 0 then -- We first check if there are any songs implemented into the system. If so, we proceed.
		sound.TimePosition = 0 -- We set the TimePosition property of our sound object to 0. This is done so when a new song starts playing, it doesn't continue from the TimePosition of when the previous song ended at.
		local selectedSong -- We create our selectedSong variable. It will be properly declared in the following code.
		
		if #queue > 0 then -- We check if there are any requested songs. If so, we select the first song that was requested.
			selectedSong = queue[1] -- Sets the selected song variable as the requested song.
			table.remove(queue, 1) -- Removes the selected song from the queue table.
			events.RefreshQueue:FireAllClients(queue) -- We fire all clients with the RefreshQueue remote event to refresh the queue as it was modified.
		else
			selectedSong = songs[math.random(1, #songs)] -- If there are no requested songs, then we select a random song from our songs table.
		end
		
		sound.SoundId = "rbxassetid://"..tostring(selectedSong.ID) -- We set the SoundId property of the sound object to our selected song's ID.
		
		if not sound.Loaded then
			sound.Loaded:Wait() -- If our song hasn't already loaded within the "nanosecond timestamp" of our setting of the sound ID, then we wait for it to load.
		end
		
		sound.PlaybackSpeed = selectedSong.Pitch or 1 -- We set the PlaybackSpeed property of the sound to the Pitch index of our selected song. If there is no pitch index, then we set it to 1.
		sound:Play() -- We begin playing the song.
        events.NewSong:FireAllClients(selectedSong.Name) -- We fire the NewSong event to all clients to indicate a new song has started playing.
		currentSong = selectedSong.Name -- We set the currentSong variable to the name of the selected song.
		sound.Ended:Wait() -- We now wait for the song to finish playing.
	else
		break -- If there isn't any songs, then we break out of the while loop.
	end
end

And that is it, we have completed our music player system. Now, as I stated at the beginning, I will not teach you how to script the client-side GUIs and such. You should have a basic understanding of how that works to properly implement it yourself. I only coded the remote events and functions on the server for you. Of course, you can add additional features and remote events/functions yourself.

I suggest reading the Sound object documentation if you wanna add features like pausing/stopping/resuming the sound.

And finally, learning about Remote Functions and Events to code the client-side part of the music player system.

Thank you for taking the time to read this tutorial. I do appreciate it. Anyway, catch ya on the next one. Cya! :grinning:

35 Likes

How would we add this to the songs table?

Here are two examples using the songs table:

local songs =  {
    {
        Name = "Song - Name"
        ID = 00000000,
        Pitch = 1
    }
}
local songs = {{Name = "Song - Name", ID = 00000000, Pitch = 1}}
1 Like

Ah okay, would you do the same for multiple songs in the table?

local songs =  {
    {
        Name = "Song - Name"
        ID = 00000000,
        Pitch = 1
    },

   {
       Name = "Song - Name 2",
       ID = 00000000,
       Pitch = 1
   }
}
3 Likes