mirror of
https://github.com/narrrl/pl8list-rewind.git
synced 2026-11-03 16:41:26 +01:00
Start drop detection from the first sound and count onsets in the debug overlay
Previews often open inside a drop; the long loudness average now covers no more than what has been heard, so that is the baseline rather than a drop.
This commit is contained in:
1 parent
856ccb3b9a
commit
e8c0f40128
2 files changed
+24
-5
No files matched your search
+14
-2
@@ -5,20 +5,32 @@ import type { Features } from "./features";
|
||||
|
||||
const KEYS: (keyof Features)[] = ["sub", "low", "mid", "high", "kick", "snare", "wobble", "drop"];
|
||||
|
||||
/// Onsets counted since the overlay opened; also on `window.audioDebug` for scripts.
|
||||
const counts = { kicks: 0, snares: 0, frames: 0 };
|
||||
|
||||
export function audioDebug(): (f: Features) => void {
|
||||
(window as unknown as { audioDebug: typeof counts }).audioDebug = counts;
|
||||
let lastAge = 99, lastSnare = 0;
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.className = "audio-debug";
|
||||
const w = (canvas.width = 240), h = (canvas.height = 110);
|
||||
const w = (canvas.width = 240), h = (canvas.height = 124);
|
||||
document.body.append(canvas);
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.font = "10px system-ui, sans-serif";
|
||||
const bar = w / KEYS.length;
|
||||
return (f) => {
|
||||
counts.frames++;
|
||||
if (f.kickAge < lastAge) counts.kicks++;
|
||||
if (f.snare > lastSnare + 0.5) counts.snares++;
|
||||
lastAge = f.kickAge;
|
||||
lastSnare = f.snare;
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
ctx.fillStyle = "#fff9";
|
||||
ctx.fillText(`kicks ${counts.kicks} · snares ${counts.snares}`, 4, 11);
|
||||
KEYS.forEach((k, i) => {
|
||||
const v = Math.min(1, Math.max(0, f[k]));
|
||||
ctx.fillStyle = k === "kick" || k === "snare" ? "#ff4d6d" : k === "drop" ? "#ffb02e" : "#7fd4ff";
|
||||
ctx.fillRect(i * bar + 3, h - 14 - v * (h - 20), bar - 6, v * (h - 20));
|
||||
ctx.fillRect(i * bar + 3, h - 14 - v * (h - 30), bar - 6, v * (h - 30));
|
||||
ctx.fillStyle = "#fff9";
|
||||
ctx.fillText(k, i * bar + 3, h - 3);
|
||||
});
|
||||
|
||||
+10
-3
@@ -43,6 +43,7 @@ const SNARE_DECAY = 0.12; // s
|
||||
const WOBBLE_SMOOTH = 0.12; // s
|
||||
const DROP_SHORT = 1; // s of low-end loudness …
|
||||
const DROP_LONG = 12; // … against this much
|
||||
const DROP_HEARD_DB = -70; // the low end counts as sounding above this
|
||||
const DROP_RISE_DB = 2.5; // dB above the long average where a drop starts
|
||||
const DROP_FULL_DB = 5; // dB above the start for a full drop
|
||||
const DROP_ATTACK = 0.25; // s
|
||||
@@ -103,6 +104,9 @@ export class FeatureTracker {
|
||||
private wobblePeak = 1;
|
||||
private short = SILENCE_DB;
|
||||
private long = SILENCE_DB;
|
||||
/// Seconds of sound heard so far: the long average covers no more than that, so
|
||||
/// music that starts in the middle of a drop is the baseline, not a drop.
|
||||
private heard = 0;
|
||||
|
||||
/// One frame from the analyser.
|
||||
fromAnalyser(an: AnalyserNode, now: number, dt: number): Features {
|
||||
@@ -172,10 +176,13 @@ export class FeatureTracker {
|
||||
this.wobblePeak = Math.max(1, speed, this.wobblePeak * Math.exp(-dt / 4));
|
||||
f.wobble += (clamp01(speed / this.wobblePeak) - f.wobble) * ease(dt, WOBBLE_SMOOTH);
|
||||
|
||||
// Start from the first sound heard, or every track would open with a drop.
|
||||
if (this.long <= SILENCE_DB) this.short = this.long = lowDb;
|
||||
if (this.heard === 0) {
|
||||
if (lowDb < DROP_HEARD_DB) return;
|
||||
this.short = this.long = lowDb;
|
||||
}
|
||||
this.heard += dt;
|
||||
this.short += (lowDb - this.short) * ease(dt, DROP_SHORT);
|
||||
this.long += (lowDb - this.long) * ease(dt, DROP_LONG);
|
||||
this.long += (lowDb - this.long) * ease(dt, Math.min(DROP_LONG, DROP_SHORT + this.heard));
|
||||
const target = clamp01((this.short - this.long - DROP_RISE_DB) / DROP_FULL_DB);
|
||||
f.drop += (target - f.drop) * ease(dt, target > f.drop ? DROP_ATTACK : DROP_RELEASE);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user