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"