using Makie, GeometryTypes
using PortAudio

N = 1024 # size of audio read
N2 = N รท 2 + 1 # size of rfft output
D = 200 # number of bins to display
M = 100 # number of lines to draw
S = 0.5 # motion speed of lines
src = PortAudioStream(1, 2)
buf = Array{Float32}(N)
fftbuf = Array{Complex{Float32}}(N2)
magbuf = Array{Float32}(N2)
fftplan = plan_rfft(buf; flags = FFTW.EXHAUSTIVE)

scene = Scene(resolution = (500, 500))
ax = axis(0:0.1:1, 0:0.1:1, 0:0.1:0.5)
center!(scene)

ls = map(1:M) do _
    yoffset = to_node(to_value(scene[:time]))
    offset = lift_node(scene[:time], yoffset) do t, yoff
        Point3f0(0.0f0, (t - yoff) * S, 0.0f0)
    end
    l = lines(
        linspace(0, 1, D),
        0.0f0,
        zeros(Float32, D),
        offset = offset,
        color = (:black, 0.1),
    )
    (yoffset, l)
end

while isopen(scene[:screen])
    for (yoffset, line) in ls
        isopen(scene[:screen]) || break
        read!(src, buf)
        A_mul_B!(fftbuf, fftplan, buf)
        @. magbuf = log(clamp(abs(fftbuf), 0.0001, Inf)) / 10 + 0.5
        line[:z] = magbuf[1:D]
        push!(yoffset, to_value(scene[:time]))
    end
end