// voice-profile.el - The VOICE signature as a pluggable PROFILE. // // Exact mirror of surface-profile.el / language-profile.el: a voice is a // [String] slot-map read via voice_get, the SAME mechanism the realizer uses // for language and surface. Where an instrument signature (a few dozen numbers) // is the timbre of a musical tone, a VOICE signature is the timbre of the vocal // tract — the instrument that renders LANGUAGE-meaning as SPEECH on the audio // surface. Physics (source-filter), not a recorded corpus. // // The signature is a few numbers, all integer (EL float arithmetic is unusable): // name - label // f0 - base pitch, Hz (glottal source rate at utterance start) // f0_end - pitch at utterance end (declination -> falling = declarative) // kf - formant scale in PER-MILLE (1000 = x1.0). Encodes vocal-tract // length: shorter tract (child/female) -> higher kf. Scales every // phoneme's nominal formant: F_actual = F_nominal * kf / 1000. // dur - speaking-rate multiplier in per-mille (1000 = nominal; >1000 slower) // tilt - source spectral tilt (per-mille; higher = darker/steeper rolloff) // breath - breathiness 0..100 (aspiration mixed into the source) // // A voice is grabbed BY EAR (voice_analyze in speech.el extracts these numbers // from a short PCM sample — an impression, not 10h of training), or declared. fn voice_new(name: String, f0: Int, f0_end: Int, kf: Int, dur: Int, tilt: Int, breath: Int) -> [String] { let r: [String] = native_list_empty() let r = native_list_append(r, "name") let r = native_list_append(r, name) let r = native_list_append(r, "f0") let r = native_list_append(r, int_to_str(f0)) let r = native_list_append(r, "f0_end") let r = native_list_append(r, int_to_str(f0_end)) let r = native_list_append(r, "kf") let r = native_list_append(r, int_to_str(kf)) let r = native_list_append(r, "dur") let r = native_list_append(r, int_to_str(dur)) let r = native_list_append(r, "tilt") let r = native_list_append(r, int_to_str(tilt)) let r = native_list_append(r, "breath") let r = native_list_append(r, int_to_str(breath)) return r } // Accessor — identical convention to surface_get / lang_get. fn voice_get(profile: [String], key: String) -> String { let n: Int = native_list_len(profile) let i: Int = 0 while i < n - 1 { let k: String = native_list_get(profile, i) if str_eq(k, key) { return native_list_get(profile, i + 1) } let i = i + 2 } return "" } fn voice_get_int(profile: [String], key: String) -> Int { let s: String = voice_get(profile, key) if str_eq(s, "") { return 0 } return str_to_int(s) } // -- Built-in voices --------------------------------------------------------- // Neuron's own voice: calm, precise, androgynous-neutral. Low-ish base pitch, // gentle declination, near-neutral vocal-tract length. fn voice_neuron() -> [String] { return voice_new("neuron", 112, 96, 1020, 1000, 1000, 6) } // Will's voice signature, built from the INGESTED geometry (f0/f0_end/kf read // back from the will-voice manifold — passed in, never hardcoded). Composable // with an accent transform exactly like voice_neuron() (voice (+) accent). fn voice_will(f0: Int, f0_end: Int, kf: Int) -> [String] { return voice_new("will", f0, f0_end, kf, 1000, 1000, 6) } // A deliberately DISTINCT target voice for the imitation proof: higher pitch, // shorter vocal tract (kf=1.20) -> a clearly different speaker. Neuron will // HEAR a sample of this voice and reconstruct these numbers by ear. fn voice_target_a() -> [String] { return voice_new("target_a", 178, 150, 1200, 950, 1000, 10) }