// 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)
}
