129 lines
4.7 KiB
JavaScript
129 lines
4.7 KiB
JavaScript
import { state } from '../state.js';
|
|
import { SceneFeature } from './SceneFeature.js';
|
|
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');
|
|
const metadataContainer = document.getElementById('metadata-container');
|
|
const songTitleElement = document.getElementById('song-title');
|
|
|
|
loadButton.addEventListener('click', () => {
|
|
fileInput.click();
|
|
});
|
|
|
|
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';
|
|
|
|
// Show metadata
|
|
songTitleElement.textContent = file.name.replace(/\.[^/.]+$/, ""); // Show filename without extension
|
|
metadataContainer.classList.remove('hidden');
|
|
|
|
const url = URL.createObjectURL(file);
|
|
state.music.player.src = url;
|
|
|
|
// Wait 5 seconds, then start the party
|
|
setTimeout(() => {
|
|
metadataContainer.classList.add('hidden');
|
|
this.startParty();
|
|
}, 5000);
|
|
}
|
|
});
|
|
|
|
state.music.player.addEventListener('ended', () => {
|
|
this.stopParty();
|
|
uiContainer.style.display = 'flex'; // Show the button again
|
|
});
|
|
}
|
|
|
|
startParty() {
|
|
state.clock.start();
|
|
state.music.player.play();
|
|
document.getElementById('ui-container').style.display = 'none';
|
|
state.partyStarted = true;
|
|
|
|
// You could add BPM detection here in the future
|
|
// For now, we use the fixed BPM
|
|
|
|
// Trigger 'start' event for other features
|
|
this.notifyFeatures('onPartyStart');
|
|
}
|
|
|
|
stopParty() {
|
|
state.clock.stop();
|
|
state.partyStarted = false;
|
|
setTimeout(() => {
|
|
const startButton = document.getElementById('loadMusicButton');
|
|
startButton.style.display = 'block';
|
|
startButton.textContent = "Party some more?"
|
|
}, 5000);
|
|
// Trigger 'end' event for other features
|
|
this.notifyFeatures('onPartyEnd');
|
|
}
|
|
|
|
notifyFeatures(methodName) {
|
|
sceneFeatureManager.features.forEach(feature => {
|
|
if (typeof feature[methodName] === 'function') {
|
|
feature[methodName]();
|
|
}
|
|
});
|
|
}
|
|
|
|
update(deltaTime) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
new MusicPlayer(); |