// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;
uniform sampler2D prgm3Texture;
uniform vec2 resolution;
uniform float time;
uniform float audiotime;
// All the fft uniforms are obtained from the AnalyserNode on the browser Audio API,
// and the Fast Fourier transform is obtained from 512 bins (fftSize).
// On PRGM1 you can find the fftTexture sampler2D uniform, created from a 512x1 px
// grayscale pseudo-texture (data texture) drawn in real-time using the AnalyserNode data.
uniform float fft; // The average of all 512 values
uniform float fftLow; // The average of the first (lower) third of the fft values Array
uniform float fftMid; // The average of the second (mid) third of the fft values Array
uniform float fftHigh; // The average of the third (high) third of the fft values Array
uniform float fftLowerHalf; // The average of the lower half of the fft values Array
uniform float fftUpperHalf; // The average of the upper half of the fft values Array
// The following values are the same as above, but normalized (0 to 1) according to...
// the ongoing registration of the maximum values ever achieved for each frequency range.
uniform float fftNormalized;
uniform float fftLowNormalized;
uniform float fftMidNormalized;
uniform float fftHighNormalized;
uniform float fftLowerHalfNormalized;
uniform float fftUpperHalfNormalized;
// https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode
vec3 clamps(vec3 x) { return clamp(x, 0.042, 1.0); }
vec3 getColor(float val, vec2 uv, float mul) {
return clamps(vec3(val * 1.0 - uv.y) * mul);
}
void main(void) {
float ratio = 0.2;
float ratioDiff = 1.0 - ratio;
float invRatioDiff = 1.0 / ratioDiff;
vec2 uv = gl_FragCoord.xy / resolution.xy;
float uvy = (uv.y / ratioDiff) - ratio * invRatioDiff;
vec4 prgm3 = texture2D(prgm3Texture, vec2(uv.x, uvy));
if (uv.y > ratio + 0.001) {
gl_FragColor = prgm3;
} else if (uv.y < ratio - 0.001) {
float huvy = uv.y / ((ratio * 2.0) - ratio);
vec2 huv = vec2(uv.x, huvy);
vec2 grid = fract(huv * 12.0) - 0.5;
vec3 col = vec3(1.0, 0.8, 0.8);
vec3 normCol = vec3(0.8, 1.0, 0.8);
vec3 color;
float mul = 100.0;
if (uv.x < 1.0 / 12.0) { color = getColor(fft, huv, mul) * col; }
else if (uv.x < 2.0 / 12.0) { color = getColor(fftLow, huv, mul) * col; }
else if (uv.x < 3.0 / 12.0) { color = getColor(fftMid, huv, mul) * col; }
else if (uv.x < 4.0 / 12.0) { color = getColor(fftHigh, huv, mul) * col; }
else if (uv.x < 5.0 / 12.0) { color = getColor(fftLowerHalf, huv, mul) * col; }
else if (uv.x < 6.0 / 12.0) { color = getColor(fftUpperHalf, huv, mul) * col; }
else if (uv.x < 7.0 / 12.0) { color = getColor(fftNormalized, huv, mul) * normCol; }
else if (uv.x < 8.0 / 12.0) { color = getColor(fftLowNormalized, huv, mul) * normCol; }
else if (uv.x < 9.0 / 12.0) { color = getColor(fftMidNormalized, huv, mul) * normCol; }
else if (uv.x < 10.0 / 12.0) { color = getColor(fftHighNormalized, huv, mul) * normCol; }
else if (uv.x < 11.0 / 12.0) { color = getColor(fftLowerHalfNormalized, huv, mul) * normCol; }
else if (uv.x < 12.0 / 12.0) { color = getColor(fftUpperHalfNormalized, huv, mul) * normCol; }
if (grid.x > 0.45 || uv.x < 0.005) color = vec3(0.0);
gl_FragColor = vec4(clamps(color), 1.0);
}
if (uv.y > ratio - 0.002 && uv.y < ratio + 0.002) {
float pattern = clamp(0.5 + (sin(-time * 5.0 + uv.x * (resolution.x / 3.0)) * 0.5 + 0.5), 0.0, 1.0);
float progress = step(uv.x * (180.0 / audiotime), 1.0);
vec3 baseColor = vec3(0.3);
vec3 progressColor = vec3(0.3, progress, 0.4) * pattern;
gl_FragColor = vec4(mix(baseColor, progressColor, progress), 1.0);
}
}
// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;
uniform sampler2D fftTexture;
uniform vec2 resolution;
uniform float time;
uniform int frame;
vec3 hash33(vec3 p3) {
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
p3 += dot(p3, p3.yxz + 19.19);
return fract((p3.xxy + p3.yxx) * p3.zyx);
}
vec3 mixColor(vec3 col1, vec3 col2, float v) {
v = clamp(v, 0.0, 1.0);
return clamp(col1 + v * (col2 - col1 * 1.5), 0.0, 1.0);
}
void main(void) {
vec2 uv = gl_FragCoord.xy / resolution.xy;
uv.x = (uv.x - 0.5 > 0.0) ? uv.x - 0.521 : 0.479 - uv.x;
vec2 p = uv * 2.0 - 1.0;
p *= vec2(resolution.x / resolution.y, 1.0);
p.y += 0.3;
vec3 col = vec3(0.0);
vec3 ref = vec3(0.0);
float nBands = 64.0;
float i = floor((uv.x * 1.3 + 0.3) * nBands);
float f = fract((uv.x * 1.3 + 0.3) * nBands);
float band = i/nBands;
band *= band * band;
band = band * 0.995;
band += 0.005;
float s = texture2D(fftTexture, vec2(band, 0.25)).x;
const int nColors = 4;
vec3 colors[nColors];
colors[0] = vec3(0.0, 0.0, 1.0);
colors[1] = vec3(0.0, 1.0, 1.0);
colors[2] = vec3(1.0, 1.0, 0.0);
colors[3] = vec3(1.0, 0.0, 0.0);
vec3 gradCol = colors[0];
float n = float(nColors) - 1.0;
for(int i = 1; i < nColors; i++) {
gradCol = mixColor(gradCol, colors[i], (s - float(i - 1) / n) * n);
}
col += vec3(1.0 - smoothstep(0.0, 0.001, p.y - s * 1.25));
col *= gradCol;
ref += vec3(1.0 - smoothstep(0.0, -0.001, p.y + s * 1.25));
ref *= gradCol * smoothstep(-0.5, 0.5, p.y);
col = mix(ref, col, smoothstep(-0.005, 0.005, p.y));
col *= smoothstep(0.125, 0.375, f);
col *= smoothstep(0.875, 0.625, f);
col = clamp(col, 0.0, 1.0);
vec3 h = hash33(vec3(gl_FragCoord.xy, float(frame)));
float dither = h.x * h.y;
col += dither * 0.04;
gl_FragColor = vec4(col,1.0);
}
// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;
uniform sampler2D prgm1Texture;
uniform vec2 resolution;
uniform float time;
uniform int frame;
vec3 hash33(vec3 p3) {
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
p3 += dot(p3, p3.yxz + 19.19);
return fract((p3.xxy + p3.yxx) * p3.zyx);
}
void main(void) {
vec2 uv = gl_FragCoord.xy / resolution.xy;
vec4 texCol = texture2D(prgm1Texture, uv);
vec4 col = texCol;
float w = 0.1;
vec2 a = vec2(uv.x - 0.5, uv.y - 0.66);
vec2 b = a * 0.15 / float(10.0);
vec3 h = hash33(vec3(gl_FragCoord.xy, frame));
uv += b * h.x;
for (float i = 1.0; i > 0.9; i-= 0.000625) {
uv -= 0.5;
uv *= i;
uv += 0.5;
col += texture2D(prgm1Texture, uv) * w * 1.5;
w *= 0.95;
}
col *= 0.9;
gl_FragColor = mix(texCol, col, 0.5);
}
// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;
uniform sampler2D prgm2Texture;
uniform vec2 resolution;
uniform float time;
uniform float fft;
uniform float fftHighNormalized;
const float PI = acos(-1.0);
const float TAU = PI * 2.0;
const float hardscan = -16.0; // -8.0 = soft | -16.0 = medium
const float hardPix = -4.0; // -2.0 = soft | -4.0 = hard
const float maskDark = 0.5;
const float maskLight = 2.5;
const float hk = 1.0 / sqrt(3.0);
vec3 hueShift(vec3 col, float a) {
const vec3 k = vec3(hk);
float ca = cos(a);
return vec3(col * ca + cross(k, col) * sin(a) + k * dot(k, col) * (1.0 - ca));
}
float toLinear(float c) {
return (c <= 0.04045) ? c / 12.92 : pow(abs((c + 0.055) / 1.055), 2.4);
}
vec3 toLinear(vec3 c) {
return vec3(toLinear(c.r), toLinear(c.g), toLinear(c.b));
}
float toSRGB(float c) {
return(c < 0.0031308 ? c * 12.92 : 1.055 * pow(abs(c), 0.41666) - 0.055);
}
vec3 toSRGB(vec3 c) {
return vec3(toSRGB(c.r), toSRGB(c.g), toSRGB(c.b));
}
vec3 fetch(vec2 pos, vec2 off, vec2 res) {
pos = floor(pos * res + off) / res;
if (max(abs(pos.x - 0.5), abs(pos.y - 0.5)) > 0.5) {
return vec3(0.0);
}
vec3 fetch = texture2D(prgm2Texture, pos.xy, -16.0).xyz;
fetch = hueShift(fetch, 1.5 * fftHighNormalized + time * 0.75);
return toLinear(mix(fetch, fetch * fetch, 0.5));
}
vec2 dist(vec2 pos, vec2 res) {
pos = pos * res;
return -((pos - floor(pos)) - vec2(0.5));
}
float gauss(float pos, float scale) {
return exp2(scale * pos * pos);
}
vec3 horz3(vec2 pos, float off, vec2 res) {
vec3 b = fetch(pos, vec2(-1.0, off), res);
vec3 c = fetch(pos, vec2(+0.0, off), res);
vec3 d = fetch(pos, vec2(+1.0, off), res);
float dst = dist(pos, res).x;
float scale = hardPix;
float wb = gauss(dst - 1.0, scale);
float wc = gauss(dst + 0.0, scale);
float wd = gauss(dst + 1.0, scale);
return (b * wb + c * wc + d * wd) / (wb + wc + wd);
}
vec3 horz5(vec2 pos, float off, vec2 res) {
vec3 a = fetch(pos, vec2(-2.0, off), res);
vec3 b = fetch(pos, vec2(-1.0, off), res);
vec3 c = fetch(pos, vec2(+0.0, off), res);
vec3 d = fetch(pos, vec2(+1.0, off), res);
vec3 e = fetch(pos, vec2(+2.0, off), res);
float dst = dist(pos, res).x;
float scale = hardPix;
float wa = gauss(dst - 2.0, scale);
float wb = gauss(dst - 1.0, scale);
float wc = gauss(dst + 0.0, scale);
float wd = gauss(dst + 1.0, scale);
float we = gauss(dst + 2.0, scale);
return (a * wa + b * wb + c * wc + d * wd + e * we) / (wa + wb + wc + wd + we);
}
float scan(vec2 pos, float off, vec2 res) {
float dst = dist(pos, res).y;
return gauss(dst + off, hardscan);
}
vec3 tri(vec2 pos, vec2 res) {
vec3 a = horz3(pos, -1.0, res);
vec3 b = horz5(pos, +0.0, res);
vec3 c = horz3(pos, +1.0, res);
float wa = scan(pos, -1.0, res);
float wb = scan(pos, +0.0, res);
float wc = scan(pos, +1.0, res);
return a * wa + b * wb + c * wc;
}
vec3 mask(vec2 pos) {
pos.x += pos.y * 3.0;
vec3 m = vec3(maskDark, maskDark, maskDark);
pos.x = fract(pos.x / 6.0);
if (pos.x < 0.333) {
m.r = maskLight;
} else if (pos.x < 0.666) {
m.g = maskLight;
} else {
m.b = maskLight;
}
return m;
}
float bar(float pos, float bar) {
pos -= bar;
return pos * pos < 4.0 ? 0.0 : 1.0;
}
vec2 warp(vec2 uv, vec2 warpAmount) {
uv = uv * 2.0 - 1.0;
vec2 offset = abs(uv.yx) / vec2(warpAmount.x, warpAmount.y);
uv = uv + uv * offset * offset;
uv = uv * 0.5 + 0.5;
return uv;
}
void drawVig(inout vec3 color, vec2 uv) {
float vignette = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y);
vignette = clamp(pow(abs(16.0 * vignette), 0.1), 0.0, 1.0);
color *= vignette;
}
void main(void) {
vec2 warpAmount = vec2(7.0, 5.0);
vec2 res = vec2(resolution.x / 4.0, resolution.y / 3.0);
vec2 uv = gl_FragCoord.xy / resolution.xy;
float vig = (0.0 + 1.0 * 21.0 * uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y));
float v = exp(-0.01 * length(uv)) * vig;
vec2 pos = mix(uv, warp(uv, warpAmount), 0.75);
vec4 color = vec4(tri(pos, res) * mask(gl_FragCoord.xy), 1.0);
color.xyz = toSRGB(color.xyz * 2.0);
color = mix(color, color * v, 0.7);
gl_FragColor = vec4(color.xyz, 1.0);
}
// ╔═════════════╦════════════════╗
// ║ Marco Gomez ║ https://mgz.me ║
// ╚═════════════╩════════════════╝
precision highp float;
// mandatory declaration for the audio buffer generation
// it will determine the audio size in seconds.
#define duration 180 // duration of the song in seconds
// you can also use it in your main function, as I did in
// this example, to have a nice time-based fadeOut effect =)
uniform vec2 resolution;
uniform float sampleRate;
uniform float blockOffset;
const float PI = acos(-1.0);
const float TAU = PI * 2.0;
float tempo = 2.125;
float hashA(float x) {
vec2 n = vec2(x * 0.99, x * 1.01);
return fract(52.982919 * fract(dot(vec2(0.06711, 0.00584), n)));
}
float hashB(float x) {
vec2 n = vec2(x * 1.01, x * 0.99);
n = fract(n * vec2(5.3987, 5.4421));
n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
float xy = n.x * n.y;
return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
}
float rnd(float x, float mn, float mx) {
return mn + floor((mx - mn) * hashA(floor(x)) * hashB(floor(x * 2.0)));
}
float nse(float x) {
float y = floor(x);
x -= y;
x = x * x * (3.0 - 2.0 * x);
return mix(hashA(y), hashA(y + 1.0), x) - 0.5;
}
vec2 voice1(float t, float f) {
vec2 v;
v.x = (
sin(t * f * TAU + sin(t * f * 80.0) * exp(t * -120.0)) * min(t * 400.0, 1.0) * exp(t * -2.0) * 0.25
);
v.y = (
cos(t * f * TAU + sin(t * f * 80.0) * exp(t * -50.0)) * min(t * 800.0, 1.0) * exp(t * -5.0) * 0.5
);
return v;
}
float voice2(float t, float f, float fmt) {
float x = fract(t * f) / f;
return (
(sin(x * 6.0 * fmt) * 0.4 + sin(x * 12.0 * fmt) + sin(x * 26.0 * fmt) * 0.2) *
min(x * 1000.0, 1.0) * exp(x * -200.0)
);
}
vec2 voice3(float t, float f) {
vec2 v = vec2(0.0, 0.0);
float fmt = 300.0 * exp2(sin(t * 0.1));
for (int i = 0; i < 16; ++i) {
float h = float(i);
float m = voice2(t + h / 3.0, f + pow(abs(2.01), (h - 8.0) * 0.2), fmt);
float pan = hashA(h);
v.x += m * pan;
v.y += m * (1.0 - pan);
}
return v * 0.1;
}
vec2 voice4(float t, float f) {
vec2 v = vec2(0.0, 0.0);
for (int i = 0; i < 8; ++i) {
float h = float(i) * 2.0 + 1.0;
float x = h;
float m = sin(t * f * TAU * x) * (1.0 + nse(h * 41.0 + t * 10.0)) / h;
float pan = hashA(h);
v.x += m * pan;
v.y += m * (1.0 - pan);
}
return v * 0.25;
}
vec2 voice5(float t, float f) {
vec2 v = vec2(0.0, 0.0);
float fmt = 12.5 * exp2(sin(t * 2.0));
for (int i = 0; i < 4; ++i) {
float h = float(i);
float m = voice2(t + h / 1.5, f + pow(abs(2.01), (h - 8.0) * 0.2), fmt);
float pan = hashA(h);
v.x += m * pan;
v.y += m * (1.0 - pan);
}
return v * 0.2;
}
float scale(float x) {
x /= 5.0;
float y = floor(x);
x = fract(x);
x *= 5.0;
return (
step(1.0, x) * 2.0 +
step(2.0, x) * 3.0 +
step(3.0, x) * 2.0 +
step(4.0, x) * 5.0 +
y * 12.0
);
}
vec2 choir(float time, float n) {
#define nt(n) pow(abs(2.0), (n + 12.0) / 12.0)
#define ss(f) smoothstep(0.0, 0.1, f)
vec2 v = voice3(time, 140.0 * pow(abs(2.0), n / 12.0));
v += voice4(-time, 140.0 * pow(abs(2.0), n / 12.0 - 1.0));
float rate = tempo * 0.25;
if (time <= 82.0 / tempo) {
float fadeIn = min(1.0, time * 0.125 * 0.75);
v += voice1(
fract(time * rate) / rate, 140.0 * 2.0 *
pow(abs(2.0), scale(rnd(time * rate, 0.0, 10.0) * 4.0) / 12.0)
) * 0.25 * fadeIn * ss(nse(time * 0.1));
v += voice5(time, 280.0 * pow(abs(2.0), n / 12.0)) * ss(nse(time * 0.1)) * 0.25;
v += voice5(time, 140.0 * pow(abs(2.0), n / 12.0)) * ss(nse(time * 0.1)) * 0.50;
v += voice5(time, 035.0 * pow(abs(2.0), n / 12.0)) * ss(nse(time * 0.1)) * 1.50;
}
if (time > 128.0 / tempo) {
v += voice3(time, 140.0 * 5.0 * nt(n)) * 0.2 * ss(nse(time * 0.44 + 10.0));
v += voice4(time, 140.0 * 4.0 * nt(n)) * 0.2 * ss(nse(time * 0.33));
v += voice3(time, 140.0 * 3.0 * nt(n)) * 0.2 * ss(nse(time * 0.12));
v += voice4(time, 140.0 * 5.0 * nt(n)) * 0.2 * ss(nse(time * 0.32 + 4.0));
}
return v;
}
vec2 snare(float t) {
if (t < 0.0) { return vec2(0.0); }
t *= 4.0;
float env = exp(t * -10.0) + exp(t * -1.0) * 0.07;
vec2 w = vec2(hashB(t), hashB(t + 0.1)) * env * 0.4;
w += sin(t * 200.0) * exp(t * -10.0) * min(1.0, t * 2500.0) * 0.1;
vec2 s = (
w *
(
max(exp(-1.0 * fract(t * 20.0)), min(t * 9.0, 1.0)) +
3.0 * clamp(1.0 - abs(t - 0.4) * 10.0, 0.0, 1.0)
)
);
return s;
}
vec2 eMix(float time) {
vec2 v = vec2(0.0);
float x = mod(time, 8.0 / tempo);
v += vec2(0.5) * sin(pow(abs(x), 0.9) * 300.0) * min(1.0, x * 200.0) * exp(x * -1.0) * 1.2;
v += vec2(0.5) * sin(pow(abs(x), 0.1) * 300.0) * min(1.0, x * 200.0) * exp(x * -5.0) * 0.7;
float rate = tempo * 2.0;
if(time > 32.0 / tempo) {
v += voice1(fract(time * rate) / rate, 140.0 * 2.0 * pow(2.0, scale(rnd(time * rate, 0.0, 10.0)) / 12.0)) * 0.4;
}
return v;
}
vec2 echo(float t) {
vec2 s = vec2(0.0);
float k = 3.0 / 4.0 / tempo;
float a = 1.0;
float damp = 0.5;
vec2 sep = vec2(0.3, 1.0);
s += eMix(t); a *= damp; sep = sep.yx;
s += eMix(t - k).yx * a * sep; a *= damp; sep = sep.yx;
s += eMix(t - k * 2.0) * a * sep; a *= damp; sep = sep.yx;
s += eMix(t - k * 3.0).yx * a * sep;
return s;
}
vec2 mainSound(float time) {
vec2 v = echo(time);
float x;
x = mod(time, 32.0 / tempo);
v += choir(time, -5.0) * clamp(x * tempo * 0.5, 0.0, 1.0) * smoothstep(16.0 + 4.0, 15.0, x * tempo);
v += choir(time, -7.0) * (clamp((x * tempo - 16.0) * 0.5, 0.0, 1.0) * smoothstep(32.0 + 4.0, 31.0, x * tempo + 1.0) + smoothstep(5.0, 0.0, x * tempo));
if(time >= 128.0 / tempo) {
v += snare(mod(time - 1.0 / tempo, 2.0 / tempo));
x = mod(time, 16.0 / tempo);
v += snare(x - tempo * (7.0 + 16.0) / 16.0);
}
vec2 ms = vec2(v.x + v.y, v.y - v.x);
v = vec2(ms.x * 0.5 + ms.y, ms.x * 0.5 - ms.y);
return v;
}
void main(void) {
vec2 coord = floor(gl_FragCoord.xy);
float time = blockOffset + (coord.x + coord.y * resolution.x) / sampleRate;
float d = float(duration);
float fadeIn = smoothstep(0.0, 2.0 * 2.125, time);
float fadeOut = clamp(abs(max(d - (2.0 * 2.125), min(d, time)) - d), 0.0, 1.0);
gl_FragColor = vec4(mainSound(time) * fadeIn * fadeOut, 0.0, 0.0);
}