136 lines
5.3 KiB
JavaScript
136 lines
5.3 KiB
JavaScript
"use strict";
|
|
|
|
const MothershipImpactSound = (function(){
|
|
|
|
// Curva de saturación analógica para darle máxima pegada sin romper el audio
|
|
const make_distortion_curve = (amount = 20) => {
|
|
const samples = 44100;
|
|
const curve = new Float32Array(samples);
|
|
const deg = Math.PI / 180;
|
|
for(let i = 0; i < samples; ++i){
|
|
const x = (i * 2) / samples - 1;
|
|
curve[i] = ((3 + amount) * x * 20 * deg) / (Math.PI + amount * Math.abs(x));
|
|
}
|
|
return curve;
|
|
};
|
|
|
|
return function(audio_ctx, output_node, volume_multiplier = 1.0){
|
|
const now = audio_ctx.currentTime;
|
|
const duration = 2.4; // Retumbe largo y cavernoso
|
|
|
|
// Bus maestro del efecto con booster de presencia
|
|
const master_bus = audio_ctx.createGain();
|
|
master_bus.gain.setValueAtTime(volume_multiplier * 1.35, now);
|
|
|
|
// Saturador suave para sonido "aplastante"
|
|
const shaper = audio_ctx.createWaveShaper();
|
|
shaper.curve = make_distortion_curve(18);
|
|
shaper.oversample = "2x";
|
|
|
|
// ========================================================
|
|
// CAPA 1: SUB-GRAVE SÍSMICO (Terremoto acústico en cabina)
|
|
// ========================================================
|
|
const sub_osc = audio_ctx.createOscillator();
|
|
const sub_gain = audio_ctx.createGain();
|
|
|
|
sub_osc.type = "sine";
|
|
sub_osc.frequency.setValueAtTime(145, now);
|
|
// Caída drástica a frecuencias casi inaudibles pero que mueven aire
|
|
sub_osc.frequency.exponentialRampToValueAtTime(22, now + 0.45);
|
|
sub_osc.frequency.setValueAtTime(20, now + duration);
|
|
|
|
sub_gain.gain.setValueAtTime(0.001, now);
|
|
sub_gain.gain.linearRampToValueAtTime(1.0, now + 0.015);
|
|
sub_gain.gain.exponentialRampToValueAtTime(0.001, now + 1.8);
|
|
|
|
sub_osc.connect(sub_gain);
|
|
sub_gain.connect(shaper);
|
|
|
|
// ========================================================
|
|
// CAPA 2: CRUJIDO DE CASCO Y METRALLA (Ráfaga de ruido blanco)
|
|
// ========================================================
|
|
const buffer_size = Math.floor(audio_ctx.sampleRate * 1.5);
|
|
const noise_buffer = audio_ctx.createBuffer(1, buffer_size, audio_ctx.sampleRate);
|
|
const noise_data = noise_buffer.getChannelData(0);
|
|
for(let i = 0; i < buffer_size; i++){
|
|
noise_data[i] = (Math.random() * 2 - 1);
|
|
}
|
|
|
|
const noise_src = audio_ctx.createBufferSource();
|
|
noise_src.buffer = noise_buffer;
|
|
|
|
const noise_filter = audio_ctx.createBiquadFilter();
|
|
noise_filter.type = "lowpass";
|
|
noise_filter.frequency.setValueAtTime(4200, now);
|
|
noise_filter.frequency.exponentialRampToValueAtTime(110, now + 1.2);
|
|
noise_filter.Q.setValueAtTime(2.5, now);
|
|
|
|
const noise_env = audio_ctx.createGain();
|
|
noise_env.gain.setValueAtTime(0.001, now);
|
|
noise_env.gain.linearRampToValueAtTime(0.9, now + 0.02);
|
|
noise_env.gain.exponentialRampToValueAtTime(0.001, now + 1.4);
|
|
|
|
noise_src.connect(noise_filter);
|
|
noise_filter.connect(noise_env);
|
|
noise_env.connect(shaper);
|
|
|
|
// ========================================================
|
|
// CAPA 3: DEFORMACIÓN METÁLICA (Resonador desafinado)
|
|
// ========================================================
|
|
const metal_osc_a = audio_ctx.createOscillator();
|
|
const metal_osc_b = audio_ctx.createOscillator();
|
|
const metal_gain = audio_ctx.createGain();
|
|
|
|
metal_osc_a.type = "sawtooth";
|
|
metal_osc_b.type = "triangle";
|
|
|
|
metal_osc_a.frequency.setValueAtTime(78, now);
|
|
metal_osc_a.frequency.exponentialRampToValueAtTime(32, now + 0.9);
|
|
|
|
metal_osc_b.frequency.setValueAtTime(114, now);
|
|
metal_osc_b.frequency.exponentialRampToValueAtTime(38, now + 0.9);
|
|
|
|
metal_gain.gain.setValueAtTime(0.001, now);
|
|
metal_gain.gain.linearRampToValueAtTime(0.55, now + 0.04);
|
|
metal_gain.gain.exponentialRampToValueAtTime(0.001, now + 1.1);
|
|
|
|
metal_osc_a.connect(metal_gain);
|
|
metal_osc_b.connect(metal_gain);
|
|
metal_gain.connect(shaper);
|
|
|
|
// ========================================================
|
|
// CAPA 4: COLA DE REVERBERACIÓN DE LA NAVE (Eco retumbante)
|
|
// ========================================================
|
|
const rumble_delay = audio_ctx.createDelay();
|
|
rumble_delay.delayTime.setValueAtTime(0.075, now);
|
|
|
|
const rumble_fb = audio_ctx.createGain();
|
|
rumble_fb.gain.setValueAtTime(0.48, now);
|
|
|
|
const rumble_filter = audio_ctx.createBiquadFilter();
|
|
rumble_filter.type = "lowpass";
|
|
rumble_filter.frequency.setValueAtTime(320, now);
|
|
|
|
rumble_delay.connect(rumble_filter);
|
|
rumble_filter.connect(rumble_fb);
|
|
rumble_fb.connect(rumble_delay);
|
|
rumble_filter.connect(master_bus);
|
|
|
|
// Conexiones de salida
|
|
shaper.connect(master_bus);
|
|
shaper.connect(rumble_delay);
|
|
master_bus.connect(output_node);
|
|
|
|
// Disparo coordinado de los generadores
|
|
sub_osc.start(now);
|
|
noise_src.start(now);
|
|
metal_osc_a.start(now);
|
|
metal_osc_b.start(now);
|
|
|
|
sub_osc.stop(now + duration);
|
|
noise_src.stop(now + 1.5);
|
|
metal_osc_a.stop(now + 1.2);
|
|
metal_osc_b.stop(now + 1.2);
|
|
};
|
|
|
|
})(); |