Oscilloscope
by MusicBar, visualizer
A CRT oscilloscope draws the live sound wave as a glowing phosphor trace over a faint graticule, with afterglow and scanlines.
How it installs, its SHA-256 and its code
Click Apply: MusicBar downloads it, checks its SHA-256 and puts it on the taskbar, or just puts it on if it already has it. Needs MusicBar 1.8 or newer.
SHA-256 6efcdbc47da34d3d3a07a9a85b1a10f11fa00c2f7c6cac6a8524c67f50b26186
//! name: Oscilloscope
//! author: MusicBar
//! kind: visualizer
//! description: A CRT oscilloscope draws the live sound wave as a glowing phosphor trace over a faint graticule, with bloom, afterglow and scanlines.
void layer(inout float3 acc, inout float cover, float3 rgb, float a)
{
a = saturate(a);
acc = rgb * a + acc * (1.0 - a);
cover = a + cover * (1.0 - a);
}
// Distance from p to the segment from a to b.
float seg(float2 p, float2 a, float2 b)
{
float2 pa = p - a;
float2 ba = b - a;
return length(pa - ba * saturate(dot(pa, ba) / dot(ba, ba)));
}
float4 main(float2 uv : TEXCOORD) : COLOR
{
float2 px = float2(uv.x * size.x, rise(uv) * size.y); // pixels: along the bar, up from the screen edge
float H = size.y;
float mid = 0.5 * H;
float amp = 0.36 * H * (0.85 + 0.2 * level);
// The wave a few pixels either side; the trace is the polyline through those points, so steep
// edges stay as thick as flat ones.
float st = max(2.0, 0.06 * H);
float w0 = wave((px.x - 2.0 * st) / size.x);
float w1 = wave((px.x - st) / size.x);
float w2 = wave(px.x / size.x);
float w3 = wave((px.x + st) / size.x);
float w4 = wave((px.x + 2.0 * st) / size.x);
float2 p0 = float2(px.x - 2.0 * st, mid + amp * w0);
float2 p1 = float2(px.x - st, mid + amp * w1);
float2 p2 = float2(px.x, mid + amp * w2);
float2 p3 = float2(px.x + st, mid + amp * w3);
float2 p4 = float2(px.x + 2.0 * st, mid + amp * w4);
float d = min(min(seg(px, p0, p1), seg(px, p1, p2)), min(seg(px, p2, p3), seg(px, p3, p4)));
// The beam moves slower where the trace is flat, so it burns brighter there.
float slope = (w3 - w1) * amp / (2.0 * st);
float flat = lerp(0.45, 1.0, 1.0 / sqrt(1.0 + slope * slope));
// Afterglow: the wave a moment ago (the same wave a little further along) and a soft blurred copy.
float wg = wave((px.x + 0.035 * size.x) / size.x);
float dGhost = abs(px.y - (mid + amp * wg * 0.92)) / sqrt(1.0 + slope * slope);
float wSoft = (w0 + w1 + w2 + w3 + w4) * 0.2;
float dSoft = abs(px.y - (mid + amp * wSoft));
// CRT: every other line a touch darker, a faint flicker, and the phosphor still glowing hardest
// just behind the sweeping beam.
float scan = 0.78 + 0.22 * step(0.5, frac(floor(px.y) * 0.5));
float flicker = 0.97 + 0.03 * sin(time * 47.0);
float sx = frac(time * 0.45) * size.x;
float behind = sx - px.x;
behind = behind < 0.0 ? behind + size.x : behind;
float crt = scan * flicker * (0.78 + 0.3 * exp(-behind / (0.18 * size.x)));
float3 acc = float3(0, 0, 0);
float cover = 0;
// The graticule: square divisions, a brighter center axis with fine ticks, fading toward the ends.
float div = 0.25 * H;
float gx = abs(frac(px.x / div + 0.5) - 0.5) * div;
float gy = abs(frac((px.y - mid) / div + 0.5) - 0.5) * div;
float grid = smoothstep(0.9, 0.2, min(gx, gy)) * step(abs(px.y - mid), 0.5 * H - 1.0);
float tickP = max(3.0, div * 0.2);
float tx = abs(frac(px.x / tickP + 0.5) - 0.5) * tickP;
float axis = smoothstep(0.9, 0.2, abs(px.y - mid)) + smoothstep(0.7, 0.1, tx) * step(abs(px.y - mid), 0.06 * H);
float ends = smoothstep(0.0, 0.08, uv.x) * smoothstep(1.0, 0.92, uv.x);
layer(acc, cover, colorB.rgb, (grid * 0.16 + saturate(axis) * 0.26) * crt * (0.4 + 0.6 * ends));
// Afterglow and bloom under the trace.
layer(acc, cover, lerp(colorB.rgb, colorA.rgb, 0.4), exp(-dSoft / (0.12 * H)) * 0.22 * crt);
layer(acc, cover, colorA.rgb, exp(-dGhost / (0.04 * H + 0.6)) * 0.28 * crt);
float bloomR = 0.08 * H * (1.0 + 0.6 * beat);
layer(acc, cover, colorA.rgb, (exp(-d / bloomR) * 0.55 + exp(-d / (0.25 * H)) * 0.18) * flat * crt * (0.8 + 0.3 * level));
// The trace: phosphor color, white-hot in the core where the beam lingers.
float core = smoothstep(0.05 * H + 0.9, 0.3, d);
layer(acc, cover, lerp(colorA.rgb, colorC.rgb, 0.3 * flat), core * crt);
layer(acc, cover, colorC.rgb, smoothstep(0.8, 0.1, d) * flat * flat * crt);
// The electron beam itself, a bright spot sweeping along the trace.
float2 spot = float2(sx, mid + amp * wave(sx / size.x));
float ds = length(px - spot);
layer(acc, cover, colorA.rgb, exp(-ds / (0.1 * H)) * 0.45);
layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.5), exp(-ds / (0.03 * H + 0.6)) * 0.9);
return paint(acc / max(cover, 0.001), cover);
}