mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-06 09:16:26 +08:00
feat(live-atc): per-position controller personas with voice and pace
Each ATC position (session + airport + type + frequency) now gets a stable persona: a controller-pool voice and a base pace of 1.1-1.3x, jittered +/-0.05 per transmission. Anything spoken without an explicit voice — the controller reply path and AI-traffic ATC lines — uses the persona; pilot voices are untouched. A new session reshuffles the shift. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -66,3 +66,32 @@ export function pilotVoiceFor(callsign: string, reserved: readonly string[] = RE
|
||||
export function controllerVoiceFor(position: string): string {
|
||||
return voiceFromPool(position.toUpperCase(), CONTROLLER_VOICES, [])
|
||||
}
|
||||
|
||||
export type ControllerPersona = {
|
||||
voice: string
|
||||
/** Controllers talk fast — base pace per position, 1.1–1.3. */
|
||||
baseSpeed: number
|
||||
}
|
||||
|
||||
/**
|
||||
* The persona of an ATC position for one session. Key convention:
|
||||
* `<sessionSeed>:<airport>:<positionType>[:<frequency>]` — the session seed
|
||||
* makes each session sound like a different shift while the position keeps
|
||||
* one consistent controller within the session.
|
||||
*/
|
||||
export function controllerPersonaFor(positionKey: string): ControllerPersona {
|
||||
const key = positionKey.toUpperCase()
|
||||
const voice = voiceFromPool(key, CONTROLLER_VOICES, [])
|
||||
// Independent hash stream for speed so voice and pace don't correlate.
|
||||
const baseSpeed = 1.1 + (fnv1a(`speed:${key}`) % 21) / 100
|
||||
return { voice, baseSpeed: Math.round(baseSpeed * 100) / 100 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-transmission pace: the persona's base speed ±0.05 — real controllers
|
||||
* don't hit the exact same tempo twice.
|
||||
*/
|
||||
export function transmissionSpeed(baseSpeed: number, rng: () => number = Math.random): number {
|
||||
const jitter = (rng() * 2 - 1) * 0.05
|
||||
return Math.round((baseSpeed + jitter) * 100) / 100
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user