Merge p10-remove-ts-smoothing into dev (drop client-side datum smoothing; waveform smoothing stays the server's job)
This commit is contained in:
@@ -263,9 +263,8 @@ const BLOB_RESTITUTION_SOFT = 0.05; // residual restitution at strength = 0 (al
|
|||||||
* the soft end → elastic reflection of the inward velocity at the hard end. The waveform
|
* the soft end → elastic reflection of the inward velocity at the hard end. The waveform
|
||||||
* is read-only authority: it pushes the fluid, the fluid never moves it.
|
* is read-only authority: it pushes the fluid, the fluid never moves it.
|
||||||
*/
|
*/
|
||||||
// Phase 10 collision retune (Daniel: "less explosive, more bouncy", no jitter, no stuck wax). The
|
// Phase 10 collision retune (Daniel: "less explosive, more bouncy", no jitter, no stuck wax).
|
||||||
// smoothed waveform (item 1) gives a gently-moving boundary, so the response can be springier without
|
// Restitution is now SUB-unity: a real bounce conserves-or-loses energy, never adds it —
|
||||||
// buzzing. Restitution is now SUB-unity: a real bounce conserves-or-loses energy, never adds it —
|
|
||||||
// over-unity (the old 1.1) injected energy each contact and read as "explosive". 0.85 at the hard end
|
// over-unity (the old 1.1) injected energy each contact and read as "explosive". 0.85 at the hard end
|
||||||
// is lively/springy; the soft end stays near-zero (mush).
|
// is lively/springy; the soft end stays near-zero (mush).
|
||||||
const WAVE_COLLIDE_SPRING = 10.0; // soft penalty stiffness pushing wax off the ribbon (slightly softer)
|
const WAVE_COLLIDE_SPRING = 10.0; // soft penalty stiffness pushing wax off the ribbon (slightly softer)
|
||||||
@@ -550,43 +549,6 @@ function decodeSamples(base64: string): Uint8Array {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Envelope-follower smoothing time constant, seconds — mirrors C#
|
|
||||||
* RmsLoudnessAlgorithm.SmoothingTimeConstantSeconds. The ~50 ms target rounds the spikey
|
|
||||||
* per-sample loudness into a smooth ribbon contour (Phase 10 tuning).
|
|
||||||
*/
|
|
||||||
const SMOOTHING_TIME_CONSTANT_SECONDS = 0.05;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Smooth the [0,255] loudness datum in place with a symmetric (zero-phase) one-pole envelope
|
|
||||||
* follower targeting SMOOTHING_TIME_CONSTANT_SECONDS. This runs at DECODE time so EXISTING stored
|
|
||||||
* mixes — whose vault profiles predate the C#-side preprocessing smoothing — read as a smooth
|
|
||||||
* curve with no data regeneration. New mixes are already smoothed at preprocessing; a second light
|
|
||||||
* pass over an already-smooth curve is near-idempotent, so applying it unconditionally here is safe.
|
|
||||||
*
|
|
||||||
* The coefficient a = exp(−secondsPerSample / τ): forward then backward pass cancels the single-pole
|
|
||||||
* lag (no time shift). Bytes stay [0,255]; we smooth in float and round back. A degenerate sample
|
|
||||||
* rate (≤0 or non-finite) leaves the data untouched.
|
|
||||||
*/
|
|
||||||
function smoothDatum(samples: Uint8Array, sampleCount: number, durationSeconds: number): void {
|
|
||||||
if (sampleCount < 2 || durationSeconds <= 0 || !Number.isFinite(durationSeconds)) return;
|
|
||||||
const secondsPerSample = durationSeconds / sampleCount;
|
|
||||||
const a = Math.exp(-secondsPerSample / SMOOTHING_TIME_CONSTANT_SECONDS);
|
|
||||||
|
|
||||||
// Float working buffer over the real samples (tail padding, if any, is untouched).
|
|
||||||
const env = new Float32Array(sampleCount);
|
|
||||||
let acc = samples[0];
|
|
||||||
for (let i = 0; i < sampleCount; i++) {
|
|
||||||
acc = a * acc + (1 - a) * samples[i];
|
|
||||||
env[i] = acc;
|
|
||||||
}
|
|
||||||
acc = env[sampleCount - 1];
|
|
||||||
for (let i = sampleCount - 1; i >= 0; i--) {
|
|
||||||
acc = a * acc + (1 - a) * env[i];
|
|
||||||
samples[i] = Math.round(Math.min(255, Math.max(0, acc)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Shaders. ─────────────────────────────────────────────────────────────────────
|
// ── Shaders. ─────────────────────────────────────────────────────────────────────
|
||||||
//
|
//
|
||||||
// Vertex: trivial pass-through. We draw a single triangle that more than covers the
|
// Vertex: trivial pass-through. We draw a single triangle that more than covers the
|
||||||
@@ -2026,11 +1988,6 @@ export function create(canvas: HTMLCanvasElement): MixVisualizerHandle {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Smooth the loudness contour at decode time so EXISTING mixes (stored before the C#-side
|
|
||||||
// preprocessing smoothing) read as a smooth curve with no regeneration. Mutates `samples` in
|
|
||||||
// place — both the GPU texture (below) and the CPU collision mirror (datum.samples) read it.
|
|
||||||
smoothDatum(samples, sampleCount, durationSeconds);
|
|
||||||
|
|
||||||
// Width = min(N, a safe power-of-two cap). The power-of-two cap (4096) is well
|
// Width = min(N, a safe power-of-two cap). The power-of-two cap (4096) is well
|
||||||
// under every real GL_MAX_TEXTURE_SIZE and keeps row arithmetic clean; we
|
// under every real GL_MAX_TEXTURE_SIZE and keeps row arithmetic clean; we
|
||||||
// still clamp it to the actual max in case a driver reports something smaller.
|
// still clamp it to the actual max in case a driver reports something smaller.
|
||||||
|
|||||||
Reference in New Issue
Block a user