sourceextensions/audio/demos/spectrum.xtl
1⍝# The music visualizer: an Ogg Vorbis (or MP3, WAV) file plays while
2⍝# X_eTaL turns what is playing into a spectrum and the spectrum into 16
3⍝# spokes in a 3D window -- Rust decodes, plays and draws; the analysis
4⍝# and the picture's geometry are X_eTaL arrays.
5⍝# Run: just demo audio spectrum (Space: pause, j/k: back/on 5 s, q: quit)
6⍝# Another file: change the path below (Ogg Vorbis, MP3 or WAV).
7
8ᵃᵘ⁼u̲se< "Audio"
9ˢᶜ⁼u̲se< "Scene"
10ˢ⁼u̲se< "Stats"
11
12a ← ᵃᵘo̲pen "demos/data/arpeggio.ogg"
13rate ← 1 s̲elect ᵃᵘi̲nfo a
14
15⍝## The analysis: 1024 samples under the playhead, a Hann taper, and the
16
17⍝# loudness at 8 frequencies an octave apart, 60 Hz to 7680 Hz, for each
18⍝# channel: one inner product with cosine and sine tables (1024 by 8)
19n ← 1024
20f ← 60.0 120.0 240.0 480.0 960.0 1920.0 3840.0 7680.0
21t ← (f̲loat r̲ange n) ÷ rate
22x ← 6.283185307179586 × t '× t̲able f
23hann ← 0.5 − 0.5 × c̲os 6.283185307179586 × (f̲loat r̲ange n) ÷ f̲loat n
24taper ← (2 c̲at n) r̲eshape hann
25ᵘl̲oudness ← { w →
26 v ← w × taper
27 re ← v '+ '× i̲nner c̲os x
28 im ← v '+ '× i̲nner s̲in x
29 m ← ((re × re) + im × im) ^ 0.5
30 1.3 × m ÷ m + 12.0
31}
32
33⍝## The picture: 16 spokes, the left channel's 8 on one half of the
34
35⍝# circle, the right's mirrored on the other; bass nearest the center;
36⍝# loudness lengthens a spoke outward and lifts its tip
37k ← f̲loat r̲ange 8
38th ← 3.141592653589793 × (k − 0.5) ÷ 8.0
39ang ← th c̲at 0.0 − th
40r0 ← 16 r̲eshape 0.35 + 0.16 × k − 1.0
41ᵘs̲pokes ← { l →
42 len ← r̲avel l
43 r1 ← r0 + len
44 cs ← c̲os ang
45 sn ← s̲in ang
46 flat ← (r0 × cs) c̲at (16 r̲eshape 0.0) c̲at (r0 × sn) c̲at (r1 × cs) c̲at (0.9 × len) c̲at r1 × sn
47 i ← r̲avel (r̲ange 16) '+ t̲able 16 × (r̲ange 6) − 1
48 16 6 r̲eshape i s̲elect flat
49}
50w ← "Spectrum -- X_eTaL" ˢᶜo̲pen! 720 540
51c ← w ˢᶜc̲amera! 0.0 0.9 3.6 0.12
52
53⍝# n by 3 points from their x, y and z columns, laid end to end
54ᵘr̲ows ← { flat →
55 n ← f̲loor (t̲ally flat) ÷ 3
56 i ← r̲avel (r̲ange n) '+ t̲able n × (r̲ange 3) − 1
57 (n c̲at 3) r̲eshape i s̲elect flat
58}
59
60⍝# a faint ring where the spokes stand
61g ← 6.283185307179586 × (f̲loat r̲ange 65) ÷ 64.0
62ring ← ((f̲loat w c̲at 4) c̲at 0.25 0.27 0.33) ˢᶜp̲olyline! ᵘr̲ows (0.3 × c̲os g) c̲at (65 r̲eshape 0.0) c̲at 0.3 × s̲in g
63
64⍝# one colored object per band: bass blue, mid green, high orange
65ᵘd̲raw ← { l →
66 m ← ᵘs̲pokes l
67 b ← ((f̲loat w c̲at 1) c̲at 0.25 0.55 1.0) ˢᶜs̲egments! 12 3 r̲eshape r̲avel (1 2 3 9 10 11) s̲elect₁ m
68 d ← ((f̲loat w c̲at 2) c̲at 0.3 0.9 0.4) ˢᶜs̲egments! 12 3 r̲eshape r̲avel (4 5 6 12 13 14) s̲elect₁ m
69 h ← ((f̲loat w c̲at 3) c̲at 1.0 0.6 0.2) ˢᶜs̲egments! 8 3 r̲eshape r̲avel (7 8 15 16) s̲elect₁ m
70 l
71}
72
73⍝## The loop: each frame read an event, then the window, then draw; the
74
75⍝# spokes ease toward the new loudness so they move smoothly
76p ← ᵃᵘp̲lay! a
77ᵘq̲uit ← { l →
78 x ← ˢᶜc̲lose! w
79 y ← ᵃᵘc̲lose! a
80 2 8 r̲eshape -1.0
81}
82ᵘk̲ey ← { e →
83 s ← ᵃᵘs̲tate a
84 (e m̲atch "key Space") × s = 1 ? ᵃᵘp̲ause! a
85 e m̲atch "key Space" ? ᵃᵘp̲lay! a
86 e m̲atch "key j" ? f̲loor a ᵃᵘs̲eek! 0.0 m̲ax (ᵃᵘp̲osition a) − 5.0
87 e m̲atch "key k" ? f̲loor a ᵃᵘs̲eek! (ᵃᵘp̲osition a) + 5.0
88 0
89}
90ᵘf̲rame ← { l →
91 0.0 > f̲irst r̲avel l ? l
92 e ← ˢᶜn̲ext! w
93 ((e m̲atch "close") + (e m̲atch "key q") + 0 = ᵃᵘs̲tate a) > 0 ? ᵘq̲uit l
94 z ← ᵘk̲ey e
95 now ← ᵘl̲oudness a ᵃᵘw̲indow n
96 ᵘd̲raw (0.6 × l) + 0.4 × now
97}
98last ← 100000 'ᵘf̲rame p̲ower 2 8 r̲eshape 0.0
99"bye"