XGravity/Public/ecma/Sounds/ShieldExplosionSound.ecma.js

87 lines
3.3 KiB
JavaScript

"use strict";
const ShieldExplosionSound = (function(){
return function(audio_ctx, output_node, volume_multiplier = 1.0){
const now = audio_ctx.currentTime;
const duration = 1.6; // Explosión profunda y larga
const preset_bus = audio_ctx.createGain();
preset_bus.gain.setValueAtTime(volume_multiplier, now);
// 1. RUIDO BROWNIANO / ROJO (El trueno profundo)
// Genera una acumulación continua de bajas frecuencias (cero agudos)
const buffer_size = Math.floor(audio_ctx.sampleRate * duration);
const buffer = audio_ctx.createBuffer(1, buffer_size, audio_ctx.sampleRate);
const data = buffer.getChannelData(0);
let last_val = 0.0;
for(let i = 0; i < buffer_size; i++){
const white = (Math.random() * 2) - 1;
// Integración para convertir ruido blanco en browniano (grave puro)
last_val = (last_val + (0.02 * white)) / 1.02;
data[i] = last_val * 3.5;
}
const rumble_source = audio_ctx.createBufferSource();
rumble_source.buffer = buffer;
// Filtro paso-bajo muy estricto: solo deja pasar el retumbe sordo
const rumble_filter = audio_ctx.createBiquadFilter();
rumble_filter.type = "lowpass";
rumble_filter.frequency.setValueAtTime(140, now);
rumble_filter.frequency.exponentialRampToValueAtTime(30, now + duration);
const rumble_gain = audio_ctx.createGain();
rumble_gain.gain.setValueAtTime(1.2, now);
// El estruendo decae lentamente como una onda expansiva real
rumble_gain.gain.exponentialRampToValueAtTime(0.001, now + duration);
rumble_source.connect(rumble_filter);
rumble_filter.connect(rumble_gain);
rumble_gain.connect(preset_bus);
rumble_source.start(now);
rumble_source.stop(now + duration);
// 2. ONDA DE CHOQUE SUBGRAVE (El golpe sísmico en el pecho)
// Desciende a frecuencias casi inaudibles pero que mueven la membrana de los cascos
const sub_osc = audio_ctx.createOscillator();
const sub_gain = audio_ctx.createGain();
sub_osc.type = "sine";
sub_osc.frequency.setValueAtTime(68, now);
sub_osc.frequency.exponentialRampToValueAtTime(18, now + 0.85);
sub_gain.gain.setValueAtTime(1.4, now);
sub_gain.gain.exponentialRampToValueAtTime(0.001, now + 0.85);
sub_osc.connect(sub_gain);
sub_gain.connect(preset_bus);
sub_osc.start(now);
sub_osc.stop(now + 0.85);
// 3. SEGUNDO OSCILADOR DE GRUÑIDO (Rumble modulado)
// Aporta fricción y textura de metal/masa estallando en el vacío
const rumble_osc = audio_ctx.createOscillator();
const rumble_osc_gain = audio_ctx.createGain();
rumble_osc.type = "triangle";
rumble_osc.frequency.setValueAtTime(45, now);
rumble_osc.frequency.exponentialRampToValueAtTime(12, now + 1.2);
rumble_osc_gain.gain.setValueAtTime(0.7, now);
rumble_osc_gain.gain.exponentialRampToValueAtTime(0.001, now + 1.2);
rumble_osc.connect(rumble_osc_gain);
rumble_osc_gain.connect(preset_bus);
rumble_osc.start(now);
rumble_osc.stop(now + 1.2);
// Salida directa hacia el bus maestro y limitador
preset_bus.connect(output_node);
};
})();