76bad46d09
Loading screen, main menu, 3D flight sim with CRT post-processing, procedural terrain, airport with buildings, low-poly aircraft, flight physics, HUD instruments, and sound. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
78 lines
2.3 KiB
JavaScript
78 lines
2.3 KiB
JavaScript
export class Sound {
|
|
constructor() {
|
|
this.ctx = null;
|
|
this.engineOsc = null;
|
|
this.engineGain = null;
|
|
this.initialized = false;
|
|
}
|
|
|
|
init() {
|
|
if (this.initialized) return;
|
|
try {
|
|
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
|
|
this.engineOsc = this.ctx.createOscillator();
|
|
this.engineOsc.type = 'sawtooth';
|
|
this.engineGain = this.ctx.createGain();
|
|
this.engineGain.gain.value = 0;
|
|
|
|
// Low-pass filter for muffled engine sound
|
|
this.engineFilter = this.ctx.createBiquadFilter();
|
|
this.engineFilter.type = 'lowpass';
|
|
this.engineFilter.frequency.value = 300;
|
|
|
|
this.engineOsc.connect(this.engineFilter);
|
|
this.engineFilter.connect(this.engineGain);
|
|
this.engineGain.connect(this.ctx.destination);
|
|
this.engineOsc.start();
|
|
this.initialized = true;
|
|
} catch {
|
|
// Audio not available, silently fail
|
|
}
|
|
}
|
|
|
|
update(throttle) {
|
|
if (!this.initialized || !this.engineOsc) return;
|
|
const baseFreq = 60;
|
|
const maxFreq = 180;
|
|
this.engineOsc.frequency.value = baseFreq + throttle * (maxFreq - baseFreq);
|
|
this.engineGain.gain.value = Math.min(throttle * 0.08, 0.08);
|
|
this.engineFilter.frequency.value = 200 + throttle * 200;
|
|
}
|
|
|
|
beep(frequency = 800, duration = 80) {
|
|
if (!this.initialized) return;
|
|
try {
|
|
const osc = this.ctx.createOscillator();
|
|
const gain = this.ctx.createGain();
|
|
osc.type = 'square';
|
|
osc.frequency.value = frequency;
|
|
gain.gain.value = 0.05;
|
|
osc.connect(gain);
|
|
gain.connect(this.ctx.destination);
|
|
osc.start();
|
|
osc.stop(this.ctx.currentTime + duration / 1000);
|
|
} catch {
|
|
// Ignore audio errors
|
|
}
|
|
}
|
|
|
|
takeoffSound() {
|
|
if (!this.initialized) return;
|
|
try {
|
|
const osc = this.ctx.createOscillator();
|
|
const gain = this.ctx.createGain();
|
|
osc.type = 'triangle';
|
|
osc.frequency.value = 400;
|
|
osc.frequency.linearRampToValueAtTime(800, this.ctx.currentTime + 0.3);
|
|
gain.gain.value = 0.08;
|
|
gain.gain.linearRampToValueAtTime(0, this.ctx.currentTime + 0.5);
|
|
osc.connect(gain);
|
|
gain.connect(this.ctx.destination);
|
|
osc.start();
|
|
osc.stop(this.ctx.currentTime + 0.5);
|
|
} catch {
|
|
// Ignore
|
|
}
|
|
}
|
|
}
|