adds some examples of scrolling spctrograms with Makie. Probably with an old version of Makie
This commit is contained in:
parent
8bd884d394
commit
207ec25f1e
2 changed files with 105 additions and 0 deletions
67
examples/waterfall_heatmap.jl
Normal file
67
examples/waterfall_heatmap.jl
Normal file
|
@ -0,0 +1,67 @@
|
|||
using Makie
|
||||
using PortAudio
|
||||
using DSP
|
||||
|
||||
"""
|
||||
Slide the values in the given matrix to the right by 1.
|
||||
The rightmosts column is discarded and the leftmost column is
|
||||
left alone.
|
||||
"""
|
||||
function shift1!(buf::AbstractMatrix)
|
||||
for col in size(buf,2):-1:2
|
||||
@. buf[:, col] = buf[:, col-1]
|
||||
end
|
||||
end
|
||||
|
||||
"""
|
||||
takes a block of audio, FFT it, and write it to the beginning of the buffer
|
||||
"""
|
||||
function processbuf!(readbuf, win, dispbuf, fftbuf, fftplan)
|
||||
readbuf .*= win
|
||||
A_mul_B!(fftbuf, fftplan, readbuf)
|
||||
shift1!(dispbuf)
|
||||
@. dispbuf[end:-1:1,1] = log(clamp(abs(fftbuf[1:D]), 0.0001, Inf))
|
||||
end
|
||||
|
||||
function processblock!(src, buf, win, dispbufs, fftbuf, fftplan)
|
||||
read!(src, buf)
|
||||
for dispbuf in dispbufs
|
||||
processbuf!(buf, win, dispbuf, fftbuf, fftplan)
|
||||
end
|
||||
end
|
||||
|
||||
N = 1024 # size of audio read
|
||||
N2 = N÷2+1 # size of rfft output
|
||||
D = 200 # number of bins to display
|
||||
M = 200 # amount of history to keep
|
||||
src = PortAudioStream(1, 2, blocksize=N)
|
||||
buf = Array{Float32}(N) # buffer for reading
|
||||
fftplan = plan_rfft(buf; flags=FFTW.EXHAUSTIVE)
|
||||
fftbuf = Array{Complex{Float32}}(N2) # destination buf for FFT
|
||||
dispbufs = [zeros(Float32, D, M) for i in 1:5, j in 1:5] # STFT bufs
|
||||
win = gaussian(N, 0.125)
|
||||
|
||||
scene = Scene(resolution=(1000,1000))
|
||||
|
||||
#pre-fill the display buffer so we can do a reasonable colormap
|
||||
for _ in 1:M
|
||||
processblock!(src, buf, win, dispbufs, fftbuf, fftplan)
|
||||
end
|
||||
|
||||
heatmaps = map(enumerate(IndexCartesian(), dispbufs)) do ibuf
|
||||
i = ibuf[1]
|
||||
buf = ibuf[2]
|
||||
|
||||
# some function of the 2D index and the value
|
||||
heatmap(buf, offset=(i[2]*size(buf, 2), i[1]*size(buf, 1)))
|
||||
end
|
||||
|
||||
center!(scene)
|
||||
|
||||
while isopen(scene[:screen])
|
||||
processblock!(src, buf, dispbufs, fftbuf, fftplan)
|
||||
for (hm, db) in zip(heatmaps, dispbufs)
|
||||
hm[:heatmap] = db
|
||||
end
|
||||
render_frame(scene)
|
||||
end
|
38
examples/waterfall_lines.jl
Normal file
38
examples/waterfall_lines.jl
Normal file
|
@ -0,0 +1,38 @@
|
|||
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, blocksize=N)
|
||||
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
|
Loading…
Reference in a new issue