JSFiddle - React, Tailwind, and code Playground
by Vasil Svetoslavov
HTML
<button onclick="sirenWail()">Wail</button>
<button onclick="sirenYelp()">Yelp</button>
<button onclick="sirenHiLo()">Hi-Lo</button>
<button onclick="sirenPiercer()">Piercer</button>
<button onclick="sirenPhaser()">Phaser</button>
<button onclick="stopSiren()">Stop</button>
<script>
/**
* Simple siren synth using Web Audio.
* Each siren uses frequency automation to make patterns.
*/
</script>
JavaScript
let _ctx = null;
let _osc = null;
let _gain = null;
function _ensureAudio() {
if (!_ctx || _ctx.state === "closed") {
_ctx = new (window.AudioContext || window.webkitAudioContext)();
}
return _ctx;
}
function stopSiren() {
if (!_ctx) return;
const now = _ctx.currentTime;
if (_gain) {
// quick fade out
_gain.gain.cancelScheduledValues(now);
_gain.gain.setValueAtTime(_gain.gain.value, now);
_gain.gain.linearRampToValueAtTime(0.0001, now + 0.06);
}
if (_osc) {
try { _osc.stop(now + 0.08); } catch {}
}
_osc = null;
_gain = null;
// Optional: keep ctx alive for faster restart. Close if you want:
// _ctx.close(); _ctx = null;
}
function _startVoice({ type = "sawtooth", volume = 0.12 } = {}) {
stopSiren(); // only one siren at a time
const ctx = _ensureAudio();
const now = ctx.currentTime;
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = type;
gain.gain.setValueAtTime(0.0001, now);
gain.gain.linearRampToValueAtTime(volume, now + 0.03);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start(now);
_osc = osc;
_gain = gain;
return { ctx, osc, gain, now };
}
/**
* 1) WAIL (slow rise/fall)
* Very common “long” siren. Typically ~500–1500 Hz sweep.
*/
function sirenWail(durationMs = 6000) {
const { ctx, osc, now } = _startVoice({ type: "sawtooth", volume: 0.12 });
const t0 = now;
const tEnd = now + durationMs / 1000;
osc.frequency.setValueAtTime(650, t0);
// Repeating slow up/down ramps
let t = t0;
const up = 1.6;
const down = 1.6;
while (t + up + down < tEnd) {
osc.frequency.linearRampToValueAtTime(1500, t + up);
osc.frequency.linearRampToValueAtTime(650, t + up + down);
t += up + down;
}
// auto stop
setTimeout(stopSiren, durationMs);
}
/**
* 2) YELP (fast wail)
* The urgent “whoop-whoop” vibe, quicker sweeps.
...