As a heads up, the AudioAnalyzer:GetSpectrum()
method that makes it possible to visualize the frequencies has been temporarily disabled for over a month now, so it won’t be possible to use that until it’s re-enabled:
Edit: It turns out that the feature has been re-enabled in some capacity! The example visualizer with the AudioPlayer
in the test place has started working again. The original post in the Audio API announcement thread still hasn’t been updated to clarify that it works again, though.
However, it was pointed out to me by another user that it currently doesn’t work with AudioDeviceInputs
(as of April 2nd, 2024), so for the time being, AudioAnalyzer:GetSpectrum()
currently cannot be used to analyze the frequencies of audio transmitted via player’s input devices (which means that it may be impossible to create the feature that you described in your post, at the moment).
Hoping that the Roblox Staff Members in the Audio API Announcement thread will be able to provide some clarification about the status of AudioAnalyzer:GetSpectrum()
and if it’ll be compatible with voice chat audio in the future.
Original Post
Unfortunately, I don’t completely understand how it works so my explanations wouldn’t be of much use. However, for anyone who is more familiar with it and would like to try to explain how this works (and potentially provide insight into how the same thing could be achieved through UI rather than parts in the Workspace, in order to answer OP’s question), here’s the client-sided code included in the Audio API Tutorial test place that makes the spectrogram / frequency visualizer functional:
local analyzer = script.Parent:WaitForChild("AudioAnalyzer")
local spectrogram = script.Parent.Spectrogram
local rng = Random.new()
local function getBins() : {Instance}
local bins : {Part} = spectrogram:GetChildren()
table.sort(bins, function(a, b)
return a.Position.X > b.Position.X
end)
return bins
end
local function lerp(lower, upper, fract)
return upper * fract + lower * (1 - fract)
end
local function getMappedBins(binCount) : {number}
local bins = analyzer:GetSpectrum()
if not bins or #bins == 0 then
local empty = {}
for i = 1, binCount do
table.insert(empty, 0)
end
return empty
end
local result = {}
for i = 1, binCount do
local j = math.pow(#bins, i / binCount)
local lower = math.max(1, math.floor(j))
local upper = math.min(#bins, math.ceil(j))
local fract = j - math.floor(j)
result[i] = lerp(bins[lower], bins[upper], fract)
result[i] = math.sqrt(result[i]) * 2
result[i] = math.clamp(result[i], 0, 10)
end
return result
end
local parts : {Part} = getBins()
while true do
local bins = getMappedBins(#parts)
for i = 1, #bins do
local part = parts[i]
local size = part.Size
part.Size = Vector3.new(size.X, math.clamp(10 * bins[i], 0, 10), size.Z)
end
task.wait()
end