feat: relay station masts come online through the toolkit chapter

This commit is contained in:
2026-10-11 08:32:33 +03:00
parent 568b0802b4
commit 33585f7e34
22 changed files with 935 additions and 2 deletions

45
src/audio/relay-tone.ts Normal file
View File

@@ -0,0 +1,45 @@
import { readSwitchboard } from '@/audio/music-pulse';
/** Tone length, seconds. */
export const RELAY_TONE_SECONDS = 0.12;
export const RELAY_TONE_GAIN = 0.12;
/** At most one tone every 0.6 s, however fast the scroll. */
export const RELAY_TONE_GAP_SECONDS = 0.6;
let lastStart = Number.NEGATIVE_INFINITY;
/**
* RELAY STATION: a mast coming online chirps once, a 120 ms sine rising
* 880 -> 1320 Hz, through the switchboard (mix bus) so mute and volume
* apply. Lazy-loaded by the scene; plays only while the soundtrack is
* running and audible; never creates an AudioContext and never throws.
*/
export function playRelayTone(): boolean {
try {
const input = readSwitchboard();
if (input === null || input.context.state !== 'running') return false;
const context = input.context;
const start = context.currentTime + 0.005;
if (start - lastStart < RELAY_TONE_GAP_SECONDS) return false;
lastStart = start;
const osc = context.createOscillator();
osc.type = 'sine';
osc.frequency.setValueAtTime(880, start);
osc.frequency.exponentialRampToValueAtTime(1320, start + RELAY_TONE_SECONDS);
const envelope = context.createGain();
envelope.gain.setValueAtTime(0, start);
envelope.gain.linearRampToValueAtTime(RELAY_TONE_GAIN, start + 0.01);
envelope.gain.exponentialRampToValueAtTime(0.0002, start + RELAY_TONE_SECONDS);
osc.connect(envelope);
envelope.connect(input);
osc.onended = () => {
osc.disconnect();
envelope.disconnect();
};
osc.start(start);
osc.stop(start + RELAY_TONE_SECONDS + 0.01);
return true;
} catch {
return false;
}
}