// speech-ingest.el - The native LOAD step of the ingest organ, for the SPEECH // primitives. Reads the acoustic-phonetics SOURCE (elp/data/phonetics.psv) and // the pronunciation lexicon SOURCE (elp/data/lexicon.psv) and emits a PHONEME // MANIFOLD into the engram: one node per phoneme (faithful, provenance-tagged // content) + is_a edges to phoneme-class nodes (a discrete manifold, not islands). // The render then PULLS phoneme geometry back from the engram via phon_geo — // zero phonetic numbers in code. Source -> manifold -> merge; the same output // the polymorphic ingest organ will produce and subsume. // -- small parsing helpers --------------------------------------------------- fn sp_map_get(pairs: [String], key: String) -> String { let n: Int = native_list_len(pairs) let i: Int = 0 while i < n - 1 { let k: String = native_list_get(pairs, i) if str_eq(k, key) { return native_list_get(pairs, i + 1) } let i = i + 2 } return "" } // read the unsigned integer that follows `key` inside string s (e.g. key "F1=") fn parse_uint_from(s: String, key: String) -> Int { let idx: Int = str_index_of(s, key) if idx < 0 { return 0 } let start: Int = idx + str_len(key) let n: Int = str_len(s) let i: Int = start let val: Int = 0 while i < n { let c: Int = str_char_code(s, i) if c >= 48 { if c <= 57 { val = val * 10 + (c - 48) i = i + 1 } else { i = n } } else { i = n } } return val } fn clean_word(w: String) -> String { let low: String = str_to_lower(w) let n: Int = str_len(low) let out: String = "" let i: Int = 0 while i < n { let c: Int = str_char_code(low, i) if c >= 97 { if c <= 122 { out = out + str_char_at(low, i) } } i = i + 1 } return out } // -- INGEST: acoustic-phonetics source -> phoneme manifold in the engram ------ // Returns the symbol -> node-id index (pmap) the render reads geometry through. fn ingest_phonetics(path: String) -> [String] { let content: String = fs_read(path) let lines: [String] = str_split(content, "\n") let nl: Int = native_list_len(lines) let pmap: [String] = native_list_empty() let classmap: [String] = native_list_empty() let li: Int = 0 while li < nl { let line: String = native_list_get(lines, li) let ll: Int = str_len(line) let skip: Int = 0 if ll < 5 { skip = 1 } if skip == 0 { let first: Int = str_char_code(line, 0) if first == 35 { skip = 1 } } if skip == 0 { let f: [String] = str_split(line, "|") let nf: Int = native_list_len(f) if nf >= 12 { let sym: String = native_list_get(f, 0) let f1: String = native_list_get(f, 1) let f2: String = native_list_get(f, 2) let f3: String = native_list_get(f, 3) let b1: String = native_list_get(f, 4) let b2: String = native_list_get(f, 5) let b3: String = native_list_get(f, 6) let vo: String = native_list_get(f, 7) let na: String = native_list_get(f, 8) let du: String = native_list_get(f, 9) let am: String = native_list_get(f, 10) let cls: String = native_list_get(f, 11) let cont: String = "phoneme " + sym + " | f1=" + f1 + " f2=" + f2 + " f3=" + f3 + " bw1=" + b1 + " bw2=" + b2 + " bw3=" + b3 + " voiced=" + vo + " nasal=" + na + " dur=" + du + " amp=" + am + " class=" + cls + " src=PetersonBarney1952-Hillenbrand1995" let id: String = engram_node(cont, "Phoneme", 80) pmap = native_list_append(pmap, sym) pmap = native_list_append(pmap, cont) // manifold edge: phoneme is_a class let cid: String = sp_map_get(classmap, cls) if str_eq(cid, "") { cid = engram_node("phoneme-class " + cls + " src=acoustic-phonetics", "PhonemeClass", 80) classmap = native_list_append(classmap, cls) classmap = native_list_append(classmap, cid) } engram_connect(id, cid, 80, "is_a") } } li = li + 1 } return pmap } // -- INGEST: pronunciation lexicon source -> word nodes ---------------------- fn ingest_lexicon(path: String) -> [String] { let content: String = fs_read(path) let lines: [String] = str_split(content, "\n") let nl: Int = native_list_len(lines) let lmap: [String] = native_list_empty() let li: Int = 0 while li < nl { let line: String = native_list_get(lines, li) let ll: Int = str_len(line) let skip: Int = 0 if ll < 3 { skip = 1 } if skip == 0 { let first: Int = str_char_code(line, 0) if first == 35 { skip = 1 } } if skip == 0 { let f: [String] = str_split(line, "|") let nf: Int = native_list_len(f) if nf >= 2 { let word: String = native_list_get(f, 0) let seq: String = native_list_get(f, 1) let id: String = engram_node("word " + word + " phonemes " + seq + " src=lexicon", "Pronunciation", 80) lmap = native_list_append(lmap, word) lmap = native_list_append(lmap, seq) } } li = li + 1 } return lmap } // -- READ geometry back from the engram (the render's afferent lookup) -------- // phon_geo(sym) -> [F1,F2,F3,B1,B2,B3,voiced,nasal,dur,amp], parsed from the // ingested phoneme node's content. NO formant numbers live in this code. fn phon_geo(pmap: [String], sym: String) -> [Int] { let id: String = sp_map_get(pmap, sym) if str_eq(id, "") { id = sp_map_get(pmap, "AX") } let out: [Int] = native_list_empty() if str_eq(id, "") { let out = native_list_append(out, 500) let out = native_list_append(out, 1500) let out = native_list_append(out, 2500) let out = native_list_append(out, 80) let out = native_list_append(out, 100) let out = native_list_append(out, 150) let out = native_list_append(out, 1) let out = native_list_append(out, 0) let out = native_list_append(out, 80) let out = native_list_append(out, 80) return out } let j: String = id let out = native_list_append(out, parse_uint_from(j, "f1=")) let out = native_list_append(out, parse_uint_from(j, "f2=")) let out = native_list_append(out, parse_uint_from(j, "f3=")) let out = native_list_append(out, parse_uint_from(j, "bw1=")) let out = native_list_append(out, parse_uint_from(j, "bw2=")) let out = native_list_append(out, parse_uint_from(j, "bw3=")) let out = native_list_append(out, parse_uint_from(j, "voiced=")) let out = native_list_append(out, parse_uint_from(j, "nasal=")) let out = native_list_append(out, parse_uint_from(j, "dur=")) let out = native_list_append(out, parse_uint_from(j, "amp=")) return out } // word -> phoneme codes, read from the ingested lexicon node. fn word_phonemes(lmap: [String], word: String) -> [String] { let id: String = sp_map_get(lmap, word) if str_eq(id, "") { let r: [String] = native_list_empty() let r = native_list_append(r, "AX") return r } return str_split(id, " ") } // realized text -> flat phoneme-code sequence (SIL between words + at ends). fn text_phonemes(lmap: [String], text: String) -> [String] { let words: [String] = str_split(text, " ") let nw: Int = native_list_len(words) let seq: [String] = native_list_empty() let seq = native_list_append(seq, "SIL") let wi: Int = 0 while wi < nw { let raw: String = native_list_get(words, wi) let w: String = clean_word(raw) if str_eq(w, "") { wi = wi + 1 } else { let ph: [String] = word_phonemes(lmap, w) let np: Int = native_list_len(ph) let pi: Int = 0 while pi < np { let code: String = native_list_get(ph, pi) seq = native_list_append(seq, code) pi = pi + 1 } seq = native_list_append(seq, "SIL") wi = wi + 1 } } return seq }