diff --git a/party-cathedral/src/scene/dancers.js b/party-cathedral/src/scene/dancers.js index 101e436..d8eacd9 100644 --- a/party-cathedral/src/scene/dancers.js +++ b/party-cathedral/src/scene/dancers.js @@ -176,7 +176,7 @@ export class Dancers extends SceneFeature { } } else { const musicTime = state.clock.getElapsedTime(); - if (state.music && state.music.beatIntensity > 0.8 && Math.random() < 0.5 && musicTime > 10) { + if (state.music && state.music.isLoudEnough && state.music.beatIntensity > 0.8 && Math.random() < 0.5 && musicTime > 10) { dancerObj.isJumping = true; dancerObj.jumpStartTime = time; } diff --git a/party-cathedral/src/scene/medieval-musicians.js b/party-cathedral/src/scene/medieval-musicians.js index b964b6f..f9dd7b9 100644 --- a/party-cathedral/src/scene/medieval-musicians.js +++ b/party-cathedral/src/scene/medieval-musicians.js @@ -245,7 +245,7 @@ export class MedievalMusicians extends SceneFeature { } else { let currentJumpChance = jumpChance * deltaTime; // Base chance over time const musicTime = state.clock.getElapsedTime(); - if (state.music && state.music.beatIntensity > 0.8 && musicTime > 15) { + if (state.music && state.music.isLoudEnough && state.music.beatIntensity > 0.8 && musicTime > 15) { currentJumpChance = 0.1; // High, fixed chance on the beat } diff --git a/party-cathedral/src/scene/music-player.js b/party-cathedral/src/scene/music-player.js index 8fb8a8c..215e942 100644 --- a/party-cathedral/src/scene/music-player.js +++ b/party-cathedral/src/scene/music-player.js @@ -1,4 +1,3 @@ -import * as THREE from 'three'; import { state } from '../state.js'; import { SceneFeature } from './SceneFeature.js'; import sceneFeatureManager from './SceneFeatureManager.js'; @@ -6,11 +5,19 @@ import sceneFeatureManager from './SceneFeatureManager.js'; export class MusicPlayer extends SceneFeature { constructor() { super(); + this.audioContext = null; + this.analyser = null; + this.source = null; + this.dataArray = null; + this.loudnessHistory = []; sceneFeatureManager.register(this); } init() { state.music.player = document.getElementById('audioPlayer'); + state.music.loudness = 0; + state.music.isLoudEnough = false; + const loadButton = document.getElementById('loadMusicButton'); const fileInput = document.getElementById('musicFileInput'); const uiContainer = document.getElementById('ui-container'); @@ -24,6 +31,17 @@ export class MusicPlayer extends SceneFeature { fileInput.addEventListener('change', (event) => { const file = event.target.files[0]; if (file) { + // Setup Web Audio API if not already done + if (!this.audioContext) { + this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + this.analyser = this.audioContext.createAnalyser(); + this.analyser.fftSize = 128; // Lower resolution is fine for loudness + this.source = this.audioContext.createMediaElementSource(state.music.player); + this.source.connect(this.analyser); + this.analyser.connect(this.audioContext.destination); + this.dataArray = new Uint8Array(this.analyser.frequencyBinCount); + } + // Hide the main button loadButton.style.display = 'none'; @@ -84,8 +102,29 @@ export class MusicPlayer extends SceneFeature { } update(deltaTime) { - // The music player updates itself via events, - // but this could be used for real-time analysis in the future. + if (!state.partyStarted || !this.analyser) return; + + this.analyser.getByteFrequencyData(this.dataArray); + + // --- Calculate current loudness --- + let sum = 0; + for (let i = 0; i < this.dataArray.length; i++) { + sum += this.dataArray[i]; + } + const average = sum / this.dataArray.length; + state.music.loudness = average / 255; // Normalize to 0-1 range + + // --- Track loudness over the last 2 seconds --- + this.loudnessHistory.push(state.music.loudness); + if (this.loudnessHistory.length > 120) { // Assuming ~60fps, 2 seconds of history + this.loudnessHistory.shift(); + } + + // --- Determine if it's loud enough to jump --- + const avgLoudness = this.loudnessHistory.reduce((a, b) => a + b, 0) / this.loudnessHistory.length; + const quietThreshold = 0.1; // Adjust this value based on testing + + state.music.isLoudEnough = avgLoudness > quietThreshold; } } diff --git a/party-cathedral/src/scene/music-visualizer.js b/party-cathedral/src/scene/music-visualizer.js index 535caf6..adeb1bf 100644 --- a/party-cathedral/src/scene/music-visualizer.js +++ b/party-cathedral/src/scene/music-visualizer.js @@ -16,6 +16,7 @@ export class MusicVisualizer extends SceneFeature { measureDuration: (60 / 120) * 4, beatIntensity: 0, measurePulse: 0, + isLoudEnough: false, }; } diff --git a/party-cathedral/src/scene/party-guests.js b/party-cathedral/src/scene/party-guests.js index f62abf7..618a4a3 100644 --- a/party-cathedral/src/scene/party-guests.js +++ b/party-cathedral/src/scene/party-guests.js @@ -155,7 +155,7 @@ export class PartyGuests extends SceneFeature { } } else { let currentJumpChance = jumpChance * deltaTime; // Base chance over time - if (state.music && state.music.beatIntensity > 0.8) { + if (state.music && state.music.isLoudEnough && state.music.beatIntensity > 0.8) { currentJumpChance = 0.1; // High, fixed chance on the beat } diff --git a/party-cathedral/src/scene/stage-torches.js b/party-cathedral/src/scene/stage-torches.js index b59e157..5354ffa 100644 --- a/party-cathedral/src/scene/stage-torches.js +++ b/party-cathedral/src/scene/stage-torches.js @@ -58,7 +58,7 @@ export class StageTorches extends SceneFeature { torchGroup.add(pointLight); // --- Particle System for Fire --- - const particleCount = 50; + const particleCount = 100; const particles = new THREE.BufferGeometry(); const positions = []; const particleData = []; @@ -107,7 +107,10 @@ export class StageTorches extends SceneFeature { this.torches.forEach(torch => { let measurePulse = 0; if (state.music) { - measurePulse = state.music.measurePulse * 4.0; // Make flames jump higher + measurePulse = state.music.measurePulse * 2.0; // Make flames jump higher + } + if (state.music.isLoudEnough) { + measurePulse += 2; } // --- Animate Particles --- @@ -119,11 +122,11 @@ export class StageTorches extends SceneFeature { const yVelocity = data.velocity.y; if (data.life <= 0 || positions[i * 3 + 1] < 0) { // Reset particle - positions[i * 3] = 0; + positions[i * 3] = (Math.random() - 0.5) * 0.2; positions[i * 3 + 1] = 1; - positions[i * 3 + 2] = 0; + positions[i * 3 + 2] = (Math.random() - 0.5) * 0.2; data.life = Math.random() * 1.0; - data.velocity.y = Math.random() * 1.5 + measurePulse; + data.velocity.y = Math.random() * 1.2 + measurePulse; } else { // Update position positions[i * 3] += data.velocity.x * deltaTime; @@ -141,6 +144,9 @@ export class StageTorches extends SceneFeature { let beatPulse = 0; if (state.music) { beatPulse = state.music.beatIntensity * 1.5; + if (state.music.isLoudEnough) { + beatPulse += 2; + } } torch.light.intensity = baseIntensity + flicker + beatPulse;