Oscilloscope
của MusicBar, visualizer
Màn hình máy hiện sóng CRT vẽ thẳng sóng âm thành vệt lân quang xanh phát sáng, có lưới đo, vệt mờ lưu lại và scanline.
Cách cài, mã SHA-256 và mã nguồn
Bấm Áp dụng: MusicBar tự tải về, kiểm tra mã SHA-256 rồi mặc lên taskbar; có rồi thì mặc luôn. Cần MusicBar 1.8 trở lên.
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);
}