programextensions/audio/demos/scope.xtl
A live oscilloscope: the synthesizer's music (Instruments.xtl) plays while a window draws the samples under the playhead -- the left channel above, the right below -- each frame, triggered on the left channel's rising zero crossing so a steady chord stands still. Run: just demo audio scope (q or close: quit)
ᵘm̲ore : Float -> Float
ᵘm̲ore ← { s → s c̲at₂ ⁱⁿb̲ar 1 + (2 s̲elect s̲hape s) d̲iv blen }
ᵘf̲eed : Num a => a -> Int -> Int
feed bar k+1 when need is 1; how many bars are queued
ᵘf̲eed ← { need k → need = 0 ? k s ← v ᵃᵘq̲ueue! ((k × blen) + r̲ange blen) s̲elect₂ song k + 1 }
ᵘt̲race : (Num a, Truthy a) => Float -> a
a trace: 256 samples as a 64 by 256 picture, each column lit from its sample's row to the next one's, so steep edges stay joined
ᵘt̲race ← { x → y ← 1 m̲ax 64 m̲in f̲loor 32.5 − 30.0 × x z ← (1 d̲rop y) c̲at -1 t̲ake y r ← r̲ange 64 (r '≥ t̲able y m̲in z) × r '≤ t̲able y m̲ax z }
ᵘt̲rigger : Float -> Int -> Int
the trigger, as a real scope's: from sample i, the first rising zero crossing of x (one sample below zero, the next at or above it) within the next 2048 samples; i itself when there is none. Drawing from it makes a steady note stand still instead of sliding.
ᵘt̲rigger ← { x i → c ← (t̲ally x) m̲in i + r̲ange 2048 s ← c s̲elect x j ← (((-1 d̲rop s) < 0.0) × (1 d̲rop s) ≥ 0.0) i̲ndexOf 1 j ≥ t̲ally c ? i (j + 1) s̲elect c }
ᵘq̲uit : (Any a, Num b) => a -> b
ᵘq̲uit ← { k → x ← ᶜᵛc̲lose! w y ← ᵃᵘc̲lose! v -1 }
ᵘf̲rame : Int -> Int
a frame: an event, the playhead, more music when less than 0.6 s is queued, and the 512 samples from the trigger (every other one) drawn: both channels triggered by the left (the bass), as a scope triggers from one channel
ᵘf̲rame ← { k → k < 0 ? k e ← ᶜᵛn̲ext! w ((e m̲atch "close") + e m̲atch "key q") > 0 ? ᵘq̲uit k p ← ᵃᵘp̲layed v ⍝ the end (within a tenth of a second: the device's count, converted ⍝ back from its own rate, can stop just short of the last frame) p ≥ total − 0.1 ? ᵘq̲uit k ahead ← ((f̲loat k × blen) ÷ ⁱⁿrate) − p k2 ← ((k < 8) × ahead < 0.6) ᵘf̲eed k i ← f̲loor p × ⁱⁿrate j ← 1 m̲ax (t̲ally left) m̲in (left ᵘt̲rigger i) + 2 × (r̲ange 256) − 1 s ← w ᶜᵛs̲how! (ᵘt̲race j s̲elect left) c̲at ᵘt̲race j s̲elect right k2 }