using Makie, GeometryTypes using PortAudio using FFTW using CairoMakie function waterfall_lines(seconds; N = 1024, # size of audio read D = 200, # number of bins to display M = 100, # number of lines to draw S = 0.5, # motion speed of lines ) PortAudioStream(1, 2) do src N2 = N รท 2 + 1 # size of rfft output buf = Array{Float32}(undef, N) fftbuf = Array{Complex{Float32}}(undef, N2) magbuf = Array{Float32}(undef, 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 done = false @sync begin @async begin while !done 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 end sleep(seconds) done = true end end end waterfall_lines(5)