local M={}
local window={}
for n=0,1024-1 do
window[n]=0.5*(1-math.cos(2*math.pi*n/(1024-1))) end
local sd
local sampleRate=48000
local channels=2
local totalSamples=0
local real,imag,mags={}, {}, {}
local rawBand,bars={}, {}
local agcRef=1e-3
local demoTime=0
local function reverseBits_arith(x,bits)
local y=0
for _=1,bits do
y=y*2+(x%2)
x=math.floor(x/2) end
return y end
local function fft_inplace(real,imag,N)
local bits=math.floor(math.log(N)/math.log(2)+0.5)
for i=0,N-1 do
local j=reverseBits_arith(i,bits)
if j>i then
local ia,ib=i+1,j+1
real[ia],real[ib]=real[ib],real[ia]
imag[ia],imag[ib]=imag[ib],imag[ia] end end
local len=2
while len<=N do
local ang=-2.0*math.pi/len
local wlen_cos=math.cos(ang)
local wlen_sin=math.sin(ang)
local i=1
while i<=N do
local w_cos,w_sin=1.0,0.0
local half=math.floor(len/2)
for j=0,half-1 do
local u_r=real[i+j]
local u_i=imag[i+j]
local v_r=real[i+j+half]*w_cos-imag[i+j+half]*w_sin
local v_i=real[i+j+half]*w_sin+imag[i+j+half]*w_cos
real[i+j]=u_r+v_r
imag[i+j]=u_i+v_i
real[i+j+half]=u_r-v_r
imag[i+j+half]=u_i-v_i
local nw_cos=w_cos*wlen_cos-w_sin*wlen_sin
local nw_sin=w_cos*wlen_sin+w_sin*wlen_cos
w_cos,w_sin=nw_cos,nw_sin end
i=i+len end
len=len*2 end end
local function clamp01(x)
if x<0 then return 0 elseif x>1 then return 1 else return x end end
local function lerp(a,b,t)return a+(b-a)*t end
local function hzToBin(hz)
local bin=math.floor((hz/sampleRate)*1024+0.5)
if bin<1 then bin=1 end
local nhalf=math.floor(1024/2)
if bin>nhalf then bin=nhalf end
return bin end
function M.load()
local snd=love.sound.newSoundData("hyperunknown_phogelbice.mp3")
channels=snd:getChannelCount()
sampleRate=snd:getSampleRate()
totalSamples=snd:getSampleCount()
sd=love.sound.newSoundData(totalSamples,sampleRate,16,1)
for i=0,totalSamples-1 do
local sum=0
for c=1,channels do
sum=sum+snd:getSample(i,c) end
sd:setSample(i,1,sum/channels) end
for i=1,36 do bars[i]=0 end
agcRef=1e-3
demoTime=0 end
function M.update(dt,timePassed)
demoTime=timePassed or demoTime
local center=math.floor(demoTime*sampleRate+0.5)
local half=math.floor(1024/2)
local start=center-half
for n=0,1024-1 do
local idx=start+n
local s=0
if idx>=0 and idx<totalSamples then
s=sd:getSample(idx,1) end
real[n+1]=s*window[n]
imag[n+1]=0 end
fft_inplace(real,imag,1024)
local nhalf=math.floor(1024/2)
for k=1,nhalf do
local r,im=real[k],imag[k]
mags[k]=math.sqrt(r*r+im*im)+1e-12 end
local binLo=hzToBin(1000)
local binHi=hzToBin(16000)
local span=binHi-binLo+1
local peakRaw=0
for i=1,36 do
local a=binLo+math.floor((i-1)*(span/36))
local b=binLo+math.floor(i*(span/36))-1
if b<a then b=a end
if b>nhalf then b=nhalf end
local accum,count=0,0
for k=a,b do
accum=accum+mags[k]
count=count+1 end
local avg=(count>0) and (accum/count) or 0.0
rawBand[i]=avg
if avg>peakRaw then peakRaw=avg end end
if peakRaw<1e-7 then peakRaw=1e-7 end
if peakRaw>agcRef then
agcRef=lerp(agcRef,peakRaw,0.30)
else
agcRef=lerp(agcRef,peakRaw,1.0-0.98) end
local scale=1.0/(agcRef*0.54+1e-7)
for i=1,36 do
local v=clamp01(rawBand[i]*scale)
if 1.25~=1.0 then
v=v^1.25 end
v=clamp01(v*0.85)
local prev=bars[i] or 0
if v>=prev then
bars[i]=lerp(prev,v,0.65)
else
bars[i]=lerp(prev,v,1-0.92) end end end
function M.draw()
local alpha
if demoTime<7.680 then
alpha=0.0
elseif demoTime<7.680+12.0 then
local t=(demoTime-7.680)/12.0
alpha=0.20*t
else
alpha=0.20 end
if alpha<=0 then return end
local W,H=love.graphics.getWidth(),love.graphics.getHeight()
local maxH=math.floor(H*0.22)
local yBottom=H-0
local w=math.floor(W/36)
if w<1 then w=1 end
local gapX=math.max(1,math.floor(w*0.15))
local bw=math.max(1,w-gapX)
love.graphics.setColor(1,1,1,alpha)
local stepY=8+6
for i=1,36 do
local h=math.floor(bars[i]*maxH+0.5)
if h>0 then
local usable=math.max(0,h-1)
local nSlats=math.floor((usable+6)/stepY)
local x=(i-1)*w
local drawn=0
for s=1,nSlats do
local y1=yBottom-drawn-8
local y2=y1+8
local yTopLimit=yBottom-h+1
if y1<yTopLimit then
y1=yTopLimit
if y1>=y2 then break end end
love.graphics.rectangle("fill",x,y1,bw,y2-y1)
drawn=drawn+stepY end
local leftover=usable-(nSlats*stepY-6)
local partialHeight=math.min(8,leftover)
if partialHeight>0 then
local y1=yBottom-nSlats*stepY-partialHeight
local yTopLimit=yBottom-h+1
if y1<yTopLimit then y1=yTopLimit end
love.graphics.rectangle("fill",x,y1,bw,partialHeight) end end end end
return M
