Seeing what is happening
How loud -- vu()
vu() the mix, left and right
vu(bass, drums) a bar each
vu(all) every sound playing
vu(bass, size:[0.04, 0.3], at:[0.97, 0.5]) slim, at the right edge
vu(stop)
Each bar is the level, a peak mark that holds and falls, and the loudest
peak in dB; over 0 dB it turns red -- clipping, heard as crackle and
recorded that way. Drag the box, or size it with size: and at: as
gui() takes them. hush() leaves it up. vu()
How hard the machine is working -- resources()
resources() a line in the corner; again to hide it
resources(at:tl) tl tr bl br
cpu 11% (core 41%) mem 38% fps 59 audio ok voices 3 paused 1 heap 13M
Watch the core: the sound is worked on one core, which fills long before the total looks high. audio late means the sound's clock is falling behind -- it is dropping out. Amber, then red, near the limit. resources()
External audio input -- adc()
The external audio input -- a microphone, a mixer's send, another
laptop into yours -- is drawn as a synth is, in a box of its own that gui()
reaches by its name, and measured for follow():
adc() the input: gui(adc, view:polar)
adc(ch:l, uid:left) a stereo input's two sides
adc(ch:r, uid:right)
gui(left, view:xy, y:right, trail:1) left against right: a goniometer
grid(3, 2)
gui(adc, view:ridge, cell:2) any view, in a cell of the grid
screen(warp:follow(adc.low, 0, 80)) the stage melting with their bass
shape(n:6, cell:free) rotate(follow(adc.amp, 0, 360))
adc(gain:4) a quiet input, four times as loud
adc(floor:-40) a noisy room: below -40 dB is silence (-50 by default)
screen(invert:follow(adc.hit, 0, 1)) a flash on every attack: a clap, a drum
grid(shuffle, trig:adc.hit) the stage dealt out again on each one
bass > scale(follow(adc.level, 0.8, 1.6)) a box pumping with the input, at any gain
adc(off:1) the input released, its boxes gone
The browser asks for the microphone the first time. See
adc() for the channels and all it measures.
The camera -- cam()
The camera on the stage, and what it sees as signals: how much moves
(cam.motion, and cam.level against its own most lately), how bright it is
(cam.bright), where the movement is (cam.x, cam.y), each burst of
movement (cam.hit):
cam() the whole view, mirrored
cam(eye, at:[0.84, 0.18], size:0.28) small, in a corner
cam(eye, cell:5) in a cell of the grid
gui(eye, hue:120, pixel:8) a box's effects on the picture
synth(uid:air, wave:pink, filter:{type:bp, freq:follow(eye.y, 3000, 150), q:8}, amp:follow(eye.level, 0, 0.12))
stars > rotate(rand(0, 360), dur:0.3, trig:eye.hit)
cam(size:2.4) screen(kaleido:6) bigger than the screen: the fold reaches the corners
cam(show:0) its signals only
cam(off) the camera let go
The examples Camera fold and Camera motion use it. See
cam() for all of it.
The mouse -- mouse.x, mouse.y
The pointer as a signal, anywhere in the window -- over the code in perform
mode too: mouse.x and mouse.y 0..1 across and down (the middle until it
moves), mouse.down 1 while pressed, mouse.hit on each press.
synth(uid:wall, wave:brown, comb:{freq:follow(mouse.x, 30, 120), fb:0.96}, crush:{bits:5, rate:follow(mouse.y, 12000, 500)}, amp:0.2)
synth(uid:s, wave:saw, freq:follow(mouse.x, 55, 880), filter:{type:lp, freq:follow(mouse.y, 4000, 200)}, amp:follow(mouse.down, 0, 0.15))
stars > rotate(rand(0, 360), dur:0.3, trig:mouse.hit)
The example Noise wall is played with it.
Drawings that follow the sound
Every sound puts signals on the bus, about 30 times a second, for
follow():
bass.fader |
its level(): 1 as written, 0 silent |
bass.level |
how loud it is now, 0..1 of its loudest lately (after the fader) |
bass.env |
a synth's envelope, 0..1 -- each note's a d s r, read from the envelope itself: a fuzz flattening the sound does not flatten it |
bass.t |
where its pitch is between the lowest and highest it has played |
bass.hit, bass.n |
1 for a moment at each step; how many so far (a poly: sound's voices stepping together are one step) |
every(4, bass.hit) |
the same on every 4th step only (the 1st, 5th, 9th...) -- any number: every(3, bass.hit), every(7, bass.hit) |
bass.low, .mid, .high |
its energy's share below 250 Hz, to 2 kHz, above -- adding up to 1, whatever its level |
bass.centroid |
its brightness, 0..1 (the spectrum's centre, 40 Hz to 8 kHz) |
bass.band(2, 4) |
the spectrum cut in n bands on a log scale (as pitch is heard), 30 Hz to 16 kHz, low to high: band k of them, each against its own loudest lately -- every band reaches 1, the treble as the bass. Made only while followed -- adc.band(2, 4) the external input's |
every(4, bass.hit) and beat.div(4) were written bass.hit4 and
beat.div4 before; those are still read.
gui(noise, size:1, view:xy, opacity:follow(noise.fader)) the drawing fades with the sound
bass > scale(follow(bass.level, 0.6, 1.4)) the box pumps with it
bass > scale(follow(bass.env, 0.8, 1.5)) ... with each note's envelope, fuzz or not
bass > scale(follow(bass.hit, 1, 1.5), decay:0.4) ... a kick on every note, falling back
screen(invert:follow(every(4, bass.hit), 0, 1)) a strobe on every 4th note
bass > rotate(follow(bass.t, 0, 360)) the pitch turns it
gui(bass, width:follow(bass.low, 0.5, 40)) thick with bass, thin without
A line run on each hit -- trig:
A line with trig: and a signal is not run at once but each time the signal
rises -- its choose() and rand() rolled afresh each time:
gui(bass, view:choose(polar, phase, xy, spectrum), trig:bass.hit) a new view each note
bass > rotate(choose(0, 90, 180, 270), trig:every(4, bass.hit)) a new angle every 4th
screen(hue:choose(0, 120, 240), trig:bass.hit) a new colour each note
gui(bass, view:choose(polar, xy), trig:adc.hit) ... or on a clap
Its patterns move one step a hit -- rand() and choose() are chance,
patterns are order:
screen(hue:Pseq(0, 90, 180, 270, inf), trig:every(4, beat.hit)) round the colour wheel, a step a bar
gui(s1, view:Pseq(polar, xy, phase, inf), trig:beat.div(2)) the views in turn, a new one every 8th
shape(uid:a, sides:Pseq(3, 4, 5, 6, inf), size:Pwhite(0.1, 0.3), trig:beat.hit) a side more each beat, a random size
a > rotate(Pseq(0, 90, 180, 270, inf), trig:beat.hit) to the next angle each beat
gui(adc, cell:Pseq(1, 2, 3, inf), stroke:Pseq(#ff2a6d, #05d9e8, inf), trig:adc.hit) each its own step: together again every 6
Patterns of other lengths drift against each other, each with its own
step. One that runs out holds its last value -- a pattern's last number is
how many times it goes round, so once through is Pseq([3, 4, 5], 1).
Run again by hand, or edited, the line starts its patterns from the top. A
sound with a rhythm of its own (dur:) keeps its patterns: they are its
notes. Struck by the hits instead (no dur:), it steps a note a hit:
synth(wave:kick, degree:Pseq(0, 3, 5, inf), trig:adc.hit).
The beat's parts count too: every(3, beat.div(4)) is every 3rd 16th --
dotted 8ths, three against the beat's two -- every(5, beat.div(4)) every
5th, drifting across the bar and round again every 5 beats; counted on the
shared clock, so in a room everyone's is the same one:
gui(s1, cell:Pseq(1, 2, 3, 4, inf), trig:every(3, beat.div(4))) a box moving in dotted 8ths
screen(kaleido:Pseq(4, 6, 8, inf), trig:every(5, beat.div(4))) a fold that drifts across the bar
While it watches, the line is tagged active. Ctrl+Enter on it again,
unchanged, switches it off -- only the watching: the beat or the sound it
follows goes on -- and the next Ctrl+Enter switches it back on. Edited, it
runs as usual and replaces its own watcher (one per cue and name), so you can
change the words or the views while it goes. trig:off in its place stops it
too; so do Ctrl+Shift+. on the line, and hush().
A line that follows a signal -- screen(invert:follow(every(4, beat.hit), 0, 1)),
s1 > rotate(follow(s1.t, 0, 360)), gui(s1, width:follow(s1.low, 0.5, 40))
-- is tagged active the same way, and Ctrl+Enter on it unchanged lets
go: it stops following (a screen() goes back to 0), the beat goes on;
press again to follow again.
Recording -- capture()
capture() the window and its sound, mp4, 30 fps
capture(size:720, fps:60, wav:1)
capture() again: stop and save
Saved in the project's recordings/. wav:1 writes the sound alone,
lossless, beside the video. The mp4's sound is laid evenly when it is
saved (the browser stamps it unevenly, and some players cut and padded
it). More
Tip: use ← → or ↑ ↓ to navigate the docs