Waveform

của MusicBar, thanh tiến trình

Cả bài hiện thành dạng sóng y như mấy app nghe nhạc, phần đã phát lên màu, mấy cột gần con trỏ thì phập phồng theo nhạc.

21 lượt tải Tải file, 4.2 KB
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 17977bfff1141839d36c0045e7c01e7d1d2c6ccf87f089a80df7b1aea81735cc

//! name: Waveform
//! author: MusicBar
//! kind: progress
//! description: The whole song drawn as a streaming-player waveform, lit up to the playhead, with the bars by the cursor breathing to the live spectrum.

// A steady random number for a bar.
float hash1(float n) { return frac(sin(n * 78.233) * 43758.5453); }

// Smooth random wobble: values that drift slowly from bar to bar.
float wobble(float x)
{
    float i = floor(x);
    float f = frac(x);
    f = f * f * (3.0 - 2.0 * f);
    return lerp(hash1(i), hash1(i + 1.0), f);
}

// The loudness of the song at t (0 to 1): intro, verse, chorus, verse, chorus, bridge, last chorus, outro.
float shape(float t)
{
    return 0.3 + 0.2 * smoothstep(0.0, 0.08, t) + 0.35 * smoothstep(0.28, 0.31, t) - 0.3 * smoothstep(0.44, 0.47, t)
         + 0.35 * smoothstep(0.58, 0.61, t) - 0.5 * smoothstep(0.77, 0.79, t) + 0.55 * smoothstep(0.84, 0.86, t)
         - 0.7 * smoothstep(0.94, 1.0, t);
}

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);
}

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 head = progress * size.x;
    float y0 = 0.34 * H;                                    // the line the bars stand on
    float tall = 0.62 * H;

    // One thin bar per cell; its height is fixed per bar, so the picture never jitters.
    float P = max(3.0, 0.14 * H);
    float i = floor(px.x / P);
    float cx = (i + 0.5) * P;
    float r = max(0.75, 0.29 * P);
    float detail = 0.45 * wobble(i * 0.23) + 0.25 * wobble(i * 0.9 + 17.0) + 0.3 * hash1(i);
    float h = shape(cx / size.x) * (0.3 + 0.75 * detail);

    // The bars by the cursor breathe with the live spectrum: bass at the cursor, treble further out.
    float k = i - floor(head / P);
    float near = exp(-abs(k) / 2.2);
    float s = spectrum(saturate(0.06 + abs(k) * 0.08));
    h *= lerp(1.0, 0.45 + 1.1 * s + 0.3 * beat, near);
    h = clamp(h, 0.06, 1.0);

    // The bar (a capsule above the line) and its short reflection below.
    float top = y0 + max(h * tall, 2.0 * r);
    float dy = px.y - clamp(px.y, y0 + r + 0.5, top - r);
    float d = length(float2(px.x - cx, dy)) - r;
    float bottom = y0 - max(h * tall * 0.42, 2.0 * r);
    float dyR = px.y - clamp(px.y, bottom + r, y0 - r - 0.5);
    float dR = length(float2(px.x - cx, dyR)) - r;
    float bar = smoothstep(0.5, -0.5, d);
    float mirror = smoothstep(0.5, -0.5, dR) * (0.25 + 0.75 * saturate((px.y - bottom) / (y0 - bottom)));

    // Played: the palette gradient up the bar, a slow sheen running through, a halo near the cursor.
    float played = smoothstep(0.5, -0.5, px.x - head);
    float t = saturate((px.y - y0) / tall);
    float3 hot = lerp(colorA.rgb, colorB.rgb, t);
    float sweep = frac(time * 0.11) * (head + 6.0 * H) - 3.0 * H;
    float sheen = exp(-abs(px.x - sweep) / (1.5 * H)) * 0.35;
    hot = lerp(hot, float3(1, 1, 1), sheen) * (0.9 + 0.2 * level);
    float3 cool = float3(0.6, 0.62, 0.68);

    float3 acc = float3(0, 0, 0);
    float cover = 0;
    float halo = exp(-max(d, 0.0) / (0.05 * H + 0.8)) * exp(-abs(px.x - head) / (2.2 * H)) * played;
    layer(acc, cover, colorA.rgb, halo * (0.25 + 0.3 * level));
    layer(acc, cover, lerp(cool, hot, played), mirror * lerp(0.2, 0.42, played));
    layer(acc, cover, lerp(cool, hot, played), bar * lerp(0.5, 1.0, played));

    // The cursor: a thin glowing line with a knob on the base line that swells on the beat.
    float dl = abs(px.x - head);
    float lineMask = step(0.05 * H, px.y) * step(px.y, 0.97 * H);
    layer(acc, cover, colorC.rgb, exp(-dl / (0.06 * H + 1.0)) * 0.35 * lineMask);
    layer(acc, cover, lerp(colorC.rgb, float3(1, 1, 1), 0.5), smoothstep(0.9, 0.2, dl) * lineMask * 0.9);
    float2 kp = px - float2(head, y0);
    float rk = 0.12 * H * (1.0 + 0.3 * beat);
    float dk = length(kp) - rk;
    layer(acc, cover, colorA.rgb, exp(-max(dk, 0.0) / (0.08 * H + 2.0 * beat)) * (0.55 + 0.4 * beat));
    layer(acc, cover, lerp(colorA.rgb, float3(1, 1, 1), 0.75 - 0.3 * smoothstep(-0.6 * rk, 0.0, dk)), smoothstep(0.5, -0.5, dk));

    return paint(acc / max(cover, 0.001), cover);
}