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)
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.
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.
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.
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)
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
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 thatsound.Amplitudedoesn’t exist, as it’s actuallysound.PlaybackLoudness.