How can I get a song's max playback loudness?

You could try something like this, but i don’t know if it would work as I haven’t tested it yet.

Filter through the song using TimePosition, recording the playbackloudness at every position.
You could do this in an instant by using a for loop and increasing by a small increment.

I am not aware of any more efficient method to find the maximum loudness that a sound will reach.

Code example:

local MaxPlaybackLoudness = 0

local Song = script.Parent.Song

for i=0,Sound.TimeLength,0.01 end
    Song.TimePosition = i
    if Song.PlaybackLoudness > MaxPlaybackLoudness then
        MaxPlaybackLoudness = Song.PlaybackLoudness
    end
end)

print(MaxPlaybackLoudness)

Hope this works better for you.

3 Likes

That wouldn’t work because a sound’s playbackloudness can’t be set, it’s something that is on goingly changed.

2 Likes

For some reason, the loop only goes once before it prints the bottom print statement.

2 Likes

I got it to work, but the song playback loudness is always 0 for some reason.

2 Likes

PlaybackLoudness only works on the client as far as I remember. It returns 0 if used on the server.

5 Likes

I am using it on the client and it can work for the server.

2 Likes

I seem to have found a solution that works, but it takes a second to run.

local MaxPlaybackLoudness = 0

local Song = script.Sound
Song:Play()

wait() -- necessary

for i=0,Song.TimeLength,0.01 do
    Song.TimePosition = i
	
	game["Run Service"].Heartbeat:Wait() -- necessary
	
    if Song.PlaybackLoudness > MaxPlaybackLoudness then
        MaxPlaybackLoudness = Song.PlaybackLoudness
    end
end
Song:Stop()

print(MaxPlaybackLoudness)

For me it always prints the highest loudness as non-zero.

The accuracy of the max loudness is exponentially less effective as you decrease the incriment. 0.001 is just as accurate as 0.01 but takes way longer to run. 0.1 is way less accurate than 0.01 but completes super fast. Just find your sweet balance between accuracy and speed, you should do fine.

It doesn’t hurt to make the client wait a second or two before allowing them to play their song.

3 Likes

Alright i don’t really know what else to tell you.

You could make like 5 of the same audio and do them all at once to maximize speed, but I personally don’t have any better working solutions.

I know I’ve seen something like this in games before though so I hope someone comes around soon and can give you a better option.

2 Likes

Thank you for @Vmena and @Dysche for helping! I shall try to to make a solution using the code and information you provided me!

2 Likes

PlaybackLoudness is arbitrary. There isn’t really a way to get this without hacking something together or running the song once over and recording the highest PlaybackLoudness received at the time of reading (which is under constant fluctuation).

Is there a specific reason why you need it? A use case wasn’t provided.

1 Like

I want it so I can use it as the max volume a song will reach, so I can use that as 1 and put all other volumes below.

1 Like

If memory serves me correctly, Volume doesn’t affect PlaybackLoudness. PlaybackLoudness is part of the audio file you uploaded itself and doesn’t take volume into account. Therefore, if you wanted to sample PlaybackLoudness, you can play an audio at volume 0 and start marking.

With that being said: I still don’t think this is the best way to go about it. Sounds with a louder volume automatically play over those with lower volumes. You can make use of the volume property, as well as SoundGroups, to throw something together.

2 Likes

As @colbert2677 covered most of it already you might want to also look into CompressorSoundEffect as it works as a normalizer to keep a consistent volume level all the time for any sound.

If you’re absolutely set on the PlaybackLoudness for other uses as well you can try this out for a more consistent result:

local RunService = game:GetService("RunService")
local SoundService = game:GetService("SoundService")

local function MaxPlaybackLoudness(soundId, scrubTime, scanAmount)
	local ListPlaybackLoudness = {}
	local MaxPlaybackLoudness = 0
	local ScanSection = 0
	local ScanFinished = false
	
	local Sound = Instance.new("Sound")
	Sound.Parent = game.SoundService
	Sound.SoundId = soundId
	
	repeat RunService.Stepped:Wait() until Sound.IsLoaded

	print("Scrubbing soundId:", Sound.SoundId)
	local startTime = tick()
	
	for soundTime = 0, Sound.TimeLength, scanAmount do
		ScanSection = ScanSection + 1
		spawn(function()
			local scrubSound = Sound:Clone()
			local startScrub = tick()
			scrubSound.Parent = game.SoundService
			scrubSound.Volume = 0
			scrubSound:Play()
			scrubSound.TimePosition = soundTime
			local ScrubStep = RunService.Stepped:Connect(function()
				table.insert(ListPlaybackLoudness, scrubSound.PlaybackLoudness)
			end)
			repeat RunService.Stepped:Wait() 
			until (tick()-startScrub) > scrubTime
			ScrubStep:Disconnect()
			scrubSound:Stop()
			scrubSound:Destroy()
			scrubSound = nil
			if ScanSection >= soundTime then 
				ScanFinished = true 
			end
		end)
	end
	repeat RunService.Stepped:Wait() until ScanFinished
	Sound:Destroy()
	Sound = nil
	print("Completed scrubbing:", tick()-startTime)
	print("Peak audio loudness:", math.max(unpack(ListPlaybackLoudness)))
end

--[[MaxPlaybackLoudness
	soundId: audio id to fetch
	scrubTime: amount of seconds to record pbl for sound instance
	scanAmount: amount of seconds to create sound instance
]]--

MaxPlaybackLoudness("rbxassetid://203626633", 2, 2)
6 Likes

just do it slow, then print the loudest it gets. put this value in the sound so you can reach it.

1 Like

i have an idea hear me out

local sound = Instance.new("Sound", game:GetService("SoundService"))
local realVolume = 0.5
local realPlaybackSpeed = 1
local maxPlaybackLoudness = 0 -- don't change this, this'll be your result
sound.SoundId = "rbxassetid://insert_the_soundid" -- insert SoundId here
if not sound.IsLoaded then sound.Loaded:Wait() end -- wait for the thing to load

sound.PlaybackSpeed = 420000 -- lmao, i just took 420 seconds (7 minutes, aka the max audio length) and add 3 more zeros for good measure
sound.Volume = 0
local con1
sound.Ended:Once(function() -- idk, useless connections are not needed so
	con1:Disconnect()
end)
con1 = sound:GetPropertyChangedSignal("PlaybackLoudness"):Connect(function() -- Heartbeat definitely won't suffice, this sound finna go too fast
	if sound.PlaybackLoudness <= maxPlaybackLoudness then return end
	maxPlaybackLoudness = sound.PlaybackLoudness
end)
sound:Play() -- do the funny
task.wait() -- surely this will take less than a frame, i doubt supercomputers that can run at thousands of fps exist rn
sound.PlaybackSpeed = realPlaybackSpeed
sound.Volume = realVolume print(maxPlaybackLoudness)
-- now, you should have the maxPlaybackLoudness? i'm not too sure if this'll work but ig it's worth a shot

i later on saw this one.

should work better then my solution.

you could play the song at like 200 times speed and record the playbackloudness very quickly then play the song and use the recorded maxplaybackloudness

This post was from 4 years ago, some properties have probably been deprecated. Use sound.PlaybackLoudness to get the actual playback volume:

local RS = game:GetService("RunService")

local sound = workspace.Sound

local volumes = {}

sound.Played:Connect(function()
    
    local getVolume = RS.Heartbeat:Connect(function()
        print(tostring(math.floor(sound.PlaybackLoudness*10)/10).."dB")
        table.insert(volumes,sound.PlaybackLoudness)
    end)
    
    sound.Ended:Wait()
    getVolume:Disconnect()
    
    local total = 0
    for _,volume in pairs(volumes) do total += volume end
    
    local ranges = {math.huge,0}
    for _,volume in pairs(volumes) do
        if ranges[1] > volume then ranges[1] = volume end
        if ranges[2] < volume then ranges[2] = volume end
    end
    
    print("- - -")
    print("Average volume: "..tostring(total/#volumes).."dB")
    print("Lowest volume: "..tostring(ranges[1]).."dB")
    print("Highest volume: "..tostring(ranges[2]).."dB")
    
end)

Edit: I did just realise that sound.Amplitude doesn’t exist, as it’s actually sound.PlaybackLoudness.

wow they updated sound properties? This changes a lot thanks

I just re-read the sound properties and there is no sound.Amplitude