Files
sternboard/web/src/sound.ts
T

45 lines
1.5 KiB
TypeScript
Raw Normal View History

// Alarma corta generada con Web Audio (sin ficheros). Dos pitidos rápidos.
let ctx: AudioContext | null = null;
export function playAlarm() {
try {
const Ctor = window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext;
ctx = ctx ?? new Ctor();
if (ctx.state === "suspended") void ctx.resume();
const now = ctx.currentTime;
for (let i = 0; i < 2; i++) {
const osc = ctx.createOscillator();
const gain = ctx.createGain();
osc.type = "square";
osc.frequency.value = 880;
const t = now + i * 0.18;
gain.gain.setValueAtTime(0.0001, t);
gain.gain.exponentialRampToValueAtTime(0.25, t + 0.01);
gain.gain.exponentialRampToValueAtTime(0.0001, t + 0.15);
osc.connect(gain);
gain.connect(ctx.destination);
osc.start(t);
osc.stop(t + 0.16);
}
} catch {
// sin audio disponible: ignoramos
}
}
// Parsea "mm", "mm:ss" o "m.5" a segundos. Devuelve null si no es válido.
export function parseTime(input: string): number | null {
const s = input.trim();
if (!s) return null;
if (s.includes(":")) {
const [m, sec] = s.split(":");
const mm = Number(m);
const ss = Number(sec);
if (!Number.isFinite(mm) || !Number.isFinite(ss) || ss < 0 || ss >= 60) return null;
const total = Math.round(mm * 60 + ss);
return total > 0 ? total : null;
}
const mins = Number(s);
if (!Number.isFinite(mins) || mins <= 0) return null;
return Math.round(mins * 60);
}