From 997986917c8339417cb4cd645456292dea8b6a36 Mon Sep 17 00:00:00 2001 From: Dejvino Date: Sun, 4 Jan 2026 17:32:28 +0000 Subject: [PATCH] Tweak: blackout thresholds (WIP) --- party-stage/src/scene/fps-counter.js | 32 ++++++++++++++- party-stage/src/scene/music-visualizer.js | 48 ++++++++++++++--------- 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/party-stage/src/scene/fps-counter.js b/party-stage/src/scene/fps-counter.js index 09f31be..e34d524 100644 --- a/party-stage/src/scene/fps-counter.js +++ b/party-stage/src/scene/fps-counter.js @@ -125,7 +125,7 @@ export class DebugPanel extends SceneFeature { this.history = new Array(this.canvas.width).fill(0); this.memHistory = new Array(this.memCanvas.width).fill(0); - this.musicHistory = new Array(this.musicCanvas.width).fill({l:0, low:0, high:0, b:0, lt:0, qt:0, m:0.5, bo: false}); + this.musicHistory = new Array(this.musicCanvas.width).fill({l:0, la:0, low:0, lla:0, high:0, b:0, lt:0, qt:0, m:0.5, bo: false, al: 0}); // Initialize visibility based on config if (state.config) { @@ -183,6 +183,8 @@ export class DebugPanel extends SceneFeature { const loudness = state.music.loudness || 0; const loudnessAvg = state.music.loudnessAverage || 0; const lows = state.music.loudnessLows || 0; + const lowsAvg = state.music.loudnessLowsAverage || 0; + const avgLoudness = state.music.averageLoudness || 0; const highs = state.music.loudnessHighs || 0; const beat = state.music.beatIntensity || 0; const thresholds = state.music.thresholds || { loud: 0, quiet: 0 }; @@ -190,7 +192,7 @@ export class DebugPanel extends SceneFeature { if (state.music.mode === 'Loud') modeVal = 1.0; else if (state.music.mode === 'Quiet') modeVal = 0.0; - this.musicHistory.push({ l: loudness, la: loudnessAvg, low: lows, high: highs, b: beat, lt: thresholds.loud, qt: thresholds.quiet, m: modeVal, bo: state.blackoutMode }); + this.musicHistory.push({ l: loudness, la: loudnessAvg, low: lows, lla: lowsAvg, high: highs, b: beat, lt: thresholds.loud, qt: thresholds.quiet, m: modeVal, bo: state.blackoutMode, al: avgLoudness }); if (this.musicHistory.length > this.musicCanvas.width) { this.musicHistory.shift(); } @@ -285,6 +287,19 @@ export class DebugPanel extends SceneFeature { } ctx.stroke(); + // Draw Lows Avg (Darker Brown) + ctx.beginPath(); + ctx.strokeStyle = '#8B4513'; // Saddle Brown + ctx.lineWidth = 1; + for (let i = 0; i < this.musicHistory.length; i++) { + const val = this.musicHistory[i].lla !== undefined ? this.musicHistory[i].lla : 0; + const x = i; + const y = h - (val * h); + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + } + ctx.stroke(); + // Draw All (Blue) ctx.beginPath(); ctx.strokeStyle = '#66aaff'; // Visible Blue @@ -324,6 +339,19 @@ export class DebugPanel extends SceneFeature { } ctx.stroke(); + // Draw Average Loudness (Pink) + ctx.beginPath(); + ctx.strokeStyle = '#FF69B4'; // HotPink + ctx.lineWidth = 1; + for (let i = 0; i < this.musicHistory.length; i++) { + const val = this.musicHistory[i].al !== undefined ? this.musicHistory[i].al : 0; + const x = i; + const y = h - (val * h); + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + } + ctx.stroke(); + // Draw Beat Intensity (Magenta) ctx.beginPath(); ctx.strokeStyle = '#ff00ff'; diff --git a/party-stage/src/scene/music-visualizer.js b/party-stage/src/scene/music-visualizer.js index eb6e287..d268005 100644 --- a/party-stage/src/scene/music-visualizer.js +++ b/party-stage/src/scene/music-visualizer.js @@ -48,7 +48,7 @@ export class MusicVisualizer extends SceneFeature { let sumLows = 0; let sumHighs = 0; let sumAll = 0; - const countLows = Math.min(dataArray.length * 0.2, dataArray.length); + const countLows = Math.min(dataArray.length * 0.4, dataArray.length); const countHighs = Math.min(dataArray.length * 0.6, dataArray.length); for (let i = 0; i < dataArray.length; i++) { @@ -70,12 +70,13 @@ export class MusicVisualizer extends SceneFeature { state.music.loudnessLows = averageLows / 255; state.music.loudnessHighs = averageHighs / 255; - // --- Track loudness over the last 2 seconds --- + // --- Track loudness over the last X seconds --- + const loudnessHistorySeconds = 0.5; this.loudnessHistory.push(state.music.loudness); - if (this.loudnessHistory.length > 120) this.loudnessHistory.shift(); + if (this.loudnessHistory.length > loudnessHistorySeconds*60) this.loudnessHistory.shift(); this.loudnessLowsHistory.push(state.music.loudnessLows); - if (this.loudnessLowsHistory.length > 120) this.loudnessLowsHistory.shift(); + if (this.loudnessLowsHistory.length > loudnessHistorySeconds*60) this.loudnessLowsHistory.shift(); const avgLoudness = this.loudnessHistory.reduce((a, b) => a + b, 0) / this.loudnessHistory.length; const avgLowsLoudness = this.loudnessLowsHistory.reduce((a, b) => a + b, 0) / this.loudnessLowsHistory.length; @@ -86,22 +87,31 @@ export class MusicVisualizer extends SceneFeature { } const time = state.clock.getElapsedTime(); - const loudness = state.music.loudness || 0; - const loudnessAvg = state.music.loudnessAverage || 0; - this.averageLoudness = loudnessAvg; + const loudness = state.music.loudnessLows || 0; + const loudnessAvg = state.music.loudnessLowsAverage || 0; + const songTime = state.music.player ? state.music.player.currentTime : 0; + this.averageLoudness = THREE.MathUtils.lerp(this.averageLoudness, loudnessAvg, deltaTime * (songTime < 5 ? 0.5 : 0.2)); + state.music.averageLoudness = this.averageLoudness; // --- Beat Detection & Auto-BPM --- - this.beatThreshold = Math.max(loudnessAvg * 1.01, this.beatThreshold * 0.96); + // Use Lows (Bass) for clearer beat detection + const beatSignal = state.music.loudnessLows || 0; + const beatAvg = state.music.loudnessLowsAverage || 0; - if (loudness > this.beatThreshold) { + // Decay threshold based on time + this.beatThreshold -= deltaTime * 0.8; + const thresholdFloor = Math.max(0.15, beatAvg * 1.1); + if (this.beatThreshold < thresholdFloor) this.beatThreshold = thresholdFloor; + + if (beatSignal > this.beatThreshold) { const now = time; - if (now - this.lastBeatTime > 0.3) { // Min interval (~200 BPM) + if (now - this.lastBeatTime > 0.25) { // Min interval (~240 BPM) const interval = now - this.lastBeatTime; this.lastBeatTime = now; - this.beatThreshold = loudness * 1.2; // Bump threshold + this.beatThreshold = beatSignal * 1.1; // Bump threshold - // Valid BPM range: 60-180 (interval 1.0s - 0.33s) - if (interval >= 0.33 && interval <= 1.0) { + // Valid BPM range: 50-200 (interval 1.2s - 0.3s) + if (interval >= 0.3 && interval <= 1.2) { this.beatIntervals.push(interval); if (this.beatIntervals.length > 8) this.beatIntervals.shift(); @@ -151,23 +161,23 @@ export class MusicVisualizer extends SceneFeature { // It starts high and decays, making it easier to exit the longer we're in blackout. const loudSpikeModif = 1.2; // How much louder than average a "drop" needs to be. let loudThreshold = this.averageLoudness * loudSpikeModif; - loudThreshold = Math.max(this.averageLoudness + 0.1, loudThreshold - (timeInStateQuiet * 0.05)); + // loudThreshold = Math.max(this.averageLoudness + 0.1, loudThreshold - (timeInStateQuiet * 0.05)); // The threshold to ENTER blackout, based on a percentage of the song's average loudness. - let quietThreshold = this.averageLoudness * 0.75; - quietThreshold = THREE.MathUtils.clamp(quietThreshold, 0.02, 0.3); // Clamp to a reasonable range. + let quietThreshold = this.averageLoudness * 0.7; + // quietThreshold = THREE.MathUtils.clamp(quietThreshold, 0.02, 0.3); // Clamp to a reasonable range. // --- Auto-Blackout Logic --- // If blackout is active, monitor for loud events (The Drop) to disable it. if (state.config.blackout) { - const beatThreshold = 0.8; + const beatThreshold = 0.7; if (state.blackoutMode) { - if (state.music.loudness > loudThreshold && state.music.beatIntensity > beatThreshold) { + if (loudness > loudThreshold && state.music.beatIntensity > beatThreshold) { state.blackoutMode = false; } } else { - if (state.music.loudness < quietThreshold) { + if (loudness < quietThreshold) { state.blackoutMode = true; } }