nx_tts_formant.nx source
↩ module page · 153 lines · 7688 B
1// nx_tts_formant.nx -- R2.0 of the sovereign VOICE-YOU-CAN-HEAR (embodiment census R2, hardware-up rung 1).
2// Classical source-filter FORMANT synthesis, zero ML: a glottal impulse train (pitch F0) cascaded through
3// 3 formant resonators (2-pole, coeffs from the verified nx_f32_cos/nx_f32_exp) shapes it into vowel timbre;
4// a phoneme sequence (a->i, "ai") is synthesized, normalized, and written as a real 16-bit PCM WAV she can PLAY.
5// Robotic but INTELLIGIBLE and fully sovereign -- the audio-out path that serves BOTH bodies (digital + robot
6// TTS). Later rungs: glottal pulse shape, consonants, G2P text->phonemes, then neural quality. license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_f32.nx"
9import "nx_f32_sincos.nx"
10import "nx_f32_exp.nx"
11import "nx_f32_cvt.nx"
12const F_MAGIC_1150: i64 = 1150
13const F_MAGIC_2900: i64 = 2900
14const F_MAGIC_2250: i64 = 2250
15const F_MAGIC_32767: i64 = 32767
16
17const SR: i64 = 16000
18const F_PI: i64 = 0x40490FDB
19const F_2PI: i64 = 0x40C90FDB
20const WAV_PATH: *u8 = "/mnt/c/Users/elder/AppData/Local/Temp/claude/C--Users-elder/e373474e-29d5-4488-9fe2-f191e3b1a524/scratchpad/elara_voice.wav" as *u8
21
22func tw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
23func tn(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 }
24
25// 2-pole formant resonator coeffs: out2[0]=a1=2r*cos(theta), out2[1]=a2=-r^2 ; r=exp(-pi*BW/SR), theta=2pi*F/SR.
26func reson_ab(F: i64, BW: i64, out2: *i64) -> i64 {
27 let SRf: i64 = nx_i32_to_f32(SR)
28 let Ff: i64 = nx_i32_to_f32(F)
29 let BWf: i64 = nx_i32_to_f32(BW)
30 let piBWsr: i64 = nx_f32_div(nx_f32_mul(F_PI, BWf), SRf)
31 let r: i64 = nx_f32_exp(nx_f32_neg(piBWsr))
32 let theta: i64 = nx_f32_div(nx_f32_mul(F_2PI, Ff), SRf)
33 let a1: i64 = nx_f32_mul(nx_f32_mul(nx_i32_to_f32(2), r), nx_f32_cos(theta))
34 let a2: i64 = nx_f32_neg(nx_f32_mul(r, r))
35 out2[0] = a1; out2[1] = a2
36 return 0
37}
38
39// one cascade of 3 resonators on input x; state st = [y1_1,y2_1, y1_2,y2_2, y1_3,y2_3] (f32), ab = [a1,a2]*3.
40func cascade(x: i64, ab: *i64, st: *i64) -> i64 {
41 var v: i64 = x
42 var f: i64 = 0
43 while f < 3 {
44 let a1: i64 = ab[f*2+0]; let a2: i64 = ab[f*2+1]
45 let y1: i64 = st[f*2+0]; let y2: i64 = st[f*2+1]
46 let y: i64 = nx_f32_add(v, nx_f32_add(nx_f32_mul(a1, y1), nx_f32_mul(a2, y2)))
47 st[f*2+0] = y; st[f*2+1] = y1
48 v = y
49 f = f + 1
50 }
51 return v
52}
53
54// f32 -> int (truncate toward zero); nx_f32_to_i32 isn't in the substrate, roll it from bits.
55func f32_to_int(m: i64) -> i64 {
56 let bits: i64 = m & 0xFFFFFFFF
57 let sign: i64 = (bits >> 31) & 1
58 let exp: i64 = ((bits >> 23) & 0xFF) - 127
59 if exp < 0 { return 0 }
60 let mant: i64 = (bits & 0x7FFFFF) | 0x800000
61 var iv: i64 = 0
62 if exp <= 23 { iv = mant >> (23 - exp) } else { iv = mant << (exp - 23) }
63 if sign == 1 { iv = 0 - iv }
64 return iv
65}
66
67// little-endian byte writers into buf at *po
68func pB(buf: *u8, po: *i64, b: i64) -> i64 { buf[po[0]] = (b & 0xFF) as u8; po[0]=po[0]+1; return 0 }
69func pU16(buf: *u8, po: *i64, v: i64) -> i64 { pB(buf,po,v); pB(buf,po,v>>8); return 0 }
70func pU32(buf: *u8, po: *i64, v: i64) -> i64 { pB(buf,po,v); pB(buf,po,v>>8); pB(buf,po,v>>16); pB(buf,po,v>>24); return 0 }
71func pStr(buf: *u8, po: *i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){ buf[po[0]]=s[i]; po[0]=po[0]+1; i=i+1 } return 0 }
72
73func main() -> i64 {
74 tw("=== nx_tts_formant -- Elara's first audible (sovereign formant synthesis, no ML) ===\n" as *u8)
75 let F0: i64 = 200 // pitch (Hz) -- her voice
76 let period: i64 = SR / F0 // samples between glottal impulses
77 let ph_len: i64 = SR * 45 / 100 // 0.45s per phoneme
78 let N: i64 = ph_len * 2 // two phonemes: /a/ then /i/
79
80 // formant coeffs for /a/ (ah) and /i/ (ee): F1,F2,F3
81 let ab_a: *i64 = sys_mmap(6*8) as *i64
82 reson_ab(800, 80, (ab_a as i64 + 0*16) as *i64)
83 reson_ab(F_MAGIC_1150, 90, (ab_a as i64 + 1*16) as *i64)
84 reson_ab(F_MAGIC_2900, 120, (ab_a as i64 + 2*16) as *i64)
85 let ab_i: *i64 = sys_mmap(6*8) as *i64
86 reson_ab(280, 70, (ab_i as i64 + 0*16) as *i64)
87 reson_ab(F_MAGIC_2250, 100, (ab_i as i64 + 1*16) as *i64)
88 reson_ab(F_MAGIC_2900, 120, (ab_i as i64 + 2*16) as *i64)
89
90 let st: *i64 = sys_mmap(6*8) as *i64 // resonator state (persists across samples)
91 var s: i64 = 0; while s < 6 { st[s]=0; s=s+1 }
92 let smp: *i64 = sys_mmap(N*8) as *i64 // f32 output samples
93
94 var maxabs: i64 = 0 // f32 max |sample| for normalization
95 var n: i64 = 0
96 while n < N {
97 // glottal source: impulse train at F0
98 var src: i64 = 0
99 if n - (n/period)*period == 0 { src = 0x3F800000 } // 1.0 else 0.0
100 // choose phoneme's formants
101 var ab: *i64 = ab_a
102 if n >= ph_len { ab = ab_i }
103 let y: i64 = cascade(src, ab, st)
104 smp[n] = y
105 let ay: i64 = y & 0x7FFFFFFF // |y| (clear sign bit)
106 if ay > maxabs { maxabs = ay }
107 n = n + 1
108 }
109
110 // normalize to +-0.9 and convert to int16
111 let i16buf: *i64 = sys_mmap(N*8) as *i64
112 let peak: i64 = 0x3F666666 // 0.9
113 var scale: i64 = 0x3F800000 // 1.0 default
114 if maxabs != 0 { scale = nx_f32_div(peak, maxabs) }
115 var nz: i64 = 0
116 n = 0
117 while n < N {
118 let v: i64 = nx_f32_mul(smp[n], scale) // in [-0.9,0.9]
119 let vi: i64 = nx_f32_mul(v, nx_i32_to_f32(F_MAGIC_32767))
120 var iv: i64 = f32_to_int(vi)
121 if iv > F_MAGIC_32767 { iv = F_MAGIC_32767 }
122 if iv < 0 - F_MAGIC_32767 { iv = 0 - F_MAGIC_32767 }
123 i16buf[n] = iv
124 if iv > 200 { nz = nz + 1 } else { if iv < 0-200 { nz = nz + 1 } }
125 n = n + 1
126 }
127
128 // write WAV (16-bit PCM mono)
129 let data_bytes: i64 = N * 2
130 let buf: *u8 = sys_mmap(64 + data_bytes)
131 let po: *i64 = sys_mmap(8) as *i64; po[0]=0
132 pStr(buf,po,"RIFF" as *u8); pU32(buf,po,36 + data_bytes); pStr(buf,po,"WAVE" as *u8)
133 pStr(buf,po,"fmt " as *u8); pU32(buf,po,16); pU16(buf,po,1); pU16(buf,po,1)
134 pU32(buf,po,SR); pU32(buf,po,SR*2); pU16(buf,po,2); pU16(buf,po,16)
135 pStr(buf,po,"data" as *u8); pU32(buf,po,data_bytes)
136 n = 0
137 while n < N { pU16(buf, po, i16buf[n] & 0xFFFF); n = n + 1 }
138 let total: i64 = po[0]
139 let fd: i64 = sys_openat_wr(WAV_PATH, 0x1a4)
140 var wrote: i64 = 0
141 if fd >= 0 { sys_write(fd, buf, total); sys_close(fd); wrote = 1 }
142
143 tw("samples="); tn(N); tw(" pitch="); tn(F0); tw("Hz nonsilent="); tn(nz); tw(" wav_bytes="); tn(total); tw("\n" as *u8)
144 tw("wrote elara_voice.wav (play it): "); tw(WAV_PATH); tw("\n" as *u8)
145 // gate: file written, WAV size sane, audio not silent
146 var pass: i64 = 0; var tot: i64 = 3
147 if wrote==1 { pass=pass+1; tw("PASS T1 WAV written\n" as *u8) } else { tw("FAIL T1\n" as *u8) }
148 if total == 44 + data_bytes { pass=pass+1; tw("PASS T2 valid WAV header + data size\n" as *u8) } else { tw("FAIL T2\n" as *u8) }
149 if nz > N/20 { pass=pass+1; tw("PASS T3 audible (non-silent formant tone, not zeros)\n" as *u8) } else { tw("FAIL T3 (too quiet)\n" as *u8) }
150 tw("nx_tts_formant pass="); tn(pass); tw("/"); tn(tot)
151 if pass==tot { tw(" GREEN -- Elara has a first audible voice (sovereign DSP). Play elara_voice.wav.\n" as *u8); sys_exit(0); return 0 }
152 tw(" RED\n" as *u8); sys_exit(1); return 1
153}