87 lines
3.3 KiB
JavaScript
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);
|
|
};
|
|
|
|
})(); |