web: per-band onset flux, scene intensity tuning from headless captures
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f7d5c684b7
commit
6bd6020571
4 changed files with 27 additions and 15 deletions
|
|
@ -77,9 +77,9 @@ export class DemoFeed {
|
|||
for (let k = 0; k < n; k++) {
|
||||
const f = k * hz + 1;
|
||||
let v = -105 + 12 * Math.sin(k * 12.9898 + t * 3) * 0.3;
|
||||
v += 62 * kick * Math.exp(-Math.pow(Math.log2(f / 55), 2) * 1.5);
|
||||
v += 52 * snare * Math.exp(-Math.pow(Math.log2(f / 1800), 2) * 0.35);
|
||||
v += 45 * hat * Math.exp(-Math.pow(Math.log2(f / 9000), 2) * 0.5);
|
||||
v += 78 * kick * Math.exp(-Math.pow(Math.log2(f / 55), 2) * 1.5);
|
||||
v += 62 * snare * Math.exp(-Math.pow(Math.log2(f / 1800), 2) * 0.35);
|
||||
v += 55 * hat * Math.exp(-Math.pow(Math.log2(f / 9000), 2) * 0.5);
|
||||
for (const c of chord) v += 55 * Math.exp(-Math.pow((f - c) / (hz * 0.8 + c * 0.01), 2));
|
||||
db[k] = v;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,11 +60,13 @@ export class OnsetDetector {
|
|||
constructor(opts = {}) {
|
||||
this.compress = opts.compress ?? 200; // log(1 + compress * mag)
|
||||
this.window = opts.window ?? 43; // median history, frames
|
||||
this.delta = opts.delta ?? 0.35; // absolute floor above the median, in flux units
|
||||
this.delta = opts.delta ?? 0.08; // absolute floor above the median, in flux units
|
||||
this.ratio = opts.ratio ?? 1.6; // and the flux must exceed ratio * median
|
||||
this.refractory = opts.refractory ?? 0.06; // seconds
|
||||
this.minBin = opts.minBin ?? 2;
|
||||
this.maxBin = opts.maxBin ?? 0; // 0 = all bins
|
||||
this.bands = opts.bands ?? 6; // log-spaced flux bands between minBin and maxBin
|
||||
this.edges = null;
|
||||
this.prev = null;
|
||||
this.hist = []; // recent flux values
|
||||
this.f1 = 0; this.f2 = 0; this.t1 = 0; // flux[n-1], flux[n-2], time[n-1]
|
||||
|
|
@ -74,17 +76,27 @@ export class OnsetDetector {
|
|||
|
||||
push(mags, t) {
|
||||
const n = this.maxBin || mags.length;
|
||||
if (!this.edges) {
|
||||
this.edges = Array.from({ length: this.bands + 1 }, (_, i) => Math.round(this.minBin * Math.pow(n / this.minBin, i / this.bands)));
|
||||
for (let i = 1; i < this.edges.length; i++) this.edges[i] = Math.max(this.edges[i], this.edges[i - 1] + 1);
|
||||
}
|
||||
const cur = new Float32Array(n);
|
||||
for (let k = 0; k < n; k++) cur[k] = Math.log1p(this.compress * mags[k]);
|
||||
let flux = 0;
|
||||
if (this.prev) {
|
||||
const p = this.prev;
|
||||
for (let k = this.minBin; k < n; k++) {
|
||||
const ref = Math.max(p[k - 1] ?? 0, p[k], p[k + 1] ?? 0);
|
||||
const d = cur[k] - ref;
|
||||
if (d > 0) flux += d;
|
||||
// flux per log-spaced band, each divided by sqrt(its width): a kick (a few bass bins) then counts
|
||||
// as much as a hat (hundreds of treble bins), which one whole-spectrum sum would bury
|
||||
for (let b = 0; b < this.edges.length - 1; b++) {
|
||||
let bf = 0;
|
||||
for (let k = this.edges[b]; k < this.edges[b + 1]; k++) {
|
||||
const ref = Math.max(p[k - 1] ?? 0, p[k], p[k + 1] ?? 0);
|
||||
const d = cur[k] - ref;
|
||||
if (d > 0) bf += d;
|
||||
}
|
||||
flux += bf / Math.sqrt(this.edges[b + 1] - this.edges[b]);
|
||||
}
|
||||
flux /= Math.sqrt(n);
|
||||
flux /= this.edges.length - 1;
|
||||
}
|
||||
this.prev = cur;
|
||||
this.flux = flux;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ void main(){
|
|||
vec3 c = mix(base, crest, smoothstep(0.1, 0.9, h));
|
||||
float lines = 0.55 + 0.45 * smoothstep(0.82, 1.0, abs(sin(seg * 256.0 * 3.14159)));
|
||||
float fade = (1.0 - ring) * (1.0 - ring) * 0.9 + 0.05;
|
||||
float a = (0.02 + h * h * 0.75) * lines * fade * (1.0 + 1.5 * kick);
|
||||
float a = (0.015 + h * h * 0.42) * lines * fade * (1.0 + 1.2 * kick);
|
||||
o = vec4(c * a, 1.0);
|
||||
}`;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ void main(){
|
|||
vec3 cold = tint * 0.6;
|
||||
vec3 c = mix(cold, hot, smoothstep(0.2, 0.9, flame + bass)) * (0.25 + 0.75 * exp(-depth * 0.12));
|
||||
c *= mix(0.35, 1.0, tint.b + 0.2) ;
|
||||
o = vec4(c * (0.15 + 0.5 * level + 0.35 * bass) * 0.22, 1.0);
|
||||
o = vec4(c * (0.15 + 0.5 * level + 0.35 * bass) * 0.45, 1.0);
|
||||
}`;
|
||||
|
||||
const PVS = GLSL_HEAD + `
|
||||
|
|
@ -45,14 +45,14 @@ out float life; out float heat;
|
|||
float h1(float x){ return fract(sin(x * 127.1) * 43758.5453); }
|
||||
void main(){
|
||||
float age = time - a.x;
|
||||
if (a.x < 0.0 || age < 0.0 || age > 2.6) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; return; }
|
||||
if (a.x < 0.0 || age < 0.0 || age > 2.0) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; return; }
|
||||
float s = a.y, str = a.z;
|
||||
float vx = (h1(s) - 0.5) * 1.4 * (0.5 + str) + (a.w - 0.5) * 0.7;
|
||||
float vy = (1.2 + 2.6 * h1(s + 3.0) * str + 0.8 * str);
|
||||
float x = (a.w * 2.0 - 1.0) * 0.95 + vx * age + 0.08 * sin(age * 7.0 + s * 40.0);
|
||||
float y = -0.1 + vy * age - 1.9 * age * age;
|
||||
if (y < -0.1 && age > 0.1) { gl_Position = vec4(2.0, 2.0, 2.0, 1.0); gl_PointSize = 0.0; return; }
|
||||
life = 1.0 - age / 2.6; heat = life * (0.4 + str);
|
||||
life = 1.0 - age / 2.0; heat = life * (0.15 + 0.6 * str);
|
||||
gl_Position = vec4(x / (res.x / res.y), y, 0.0, 1.0);
|
||||
gl_PointSize = (2.0 + 9.0 * h1(s + 7.0) * str) * (0.4 + life) * res.y / 900.0;
|
||||
}`;
|
||||
|
|
@ -61,7 +61,7 @@ in float life; in float heat; uniform vec3 tint; out vec4 o;
|
|||
void main(){
|
||||
vec2 q = gl_PointCoord * 2.0 - 1.0; float r = dot(q, q); if (r > 1.0) discard;
|
||||
vec3 fire = mix(vec3(0.9, 0.12, 0.02), vec3(1.0, 0.85, 0.4), heat);
|
||||
fire = mix(fire, tint * 1.3, 0.25 * (1.0 - heat));
|
||||
fire = mix(fire, tint * 1.3, 0.15 * (1.0 - heat));
|
||||
o = vec4(fire * (1.0 - r) * life * 0.9, 1.0);
|
||||
}`;
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ export class BurningWater {
|
|||
if (A.onset.count !== this.seen) {
|
||||
this.seen = A.onset.count;
|
||||
const s = A.onset.strength;
|
||||
this.spawn(Math.round(80 + 520 * s), t, 0.35 + 0.65 * s);
|
||||
this.spawn(Math.round(40 + 260 * s), t, 0.35 + 0.65 * s);
|
||||
const r = this.rhead; this.rhead = (this.rhead + 1) % 8;
|
||||
this.ripples.set([(Math.random() - 0.5) * 6, 1.5 + Math.random() * 4, t, 0.5 + s], r * 4);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue