organ: the rest of the peripheral moves into El
El SDK CI - dev / build-and-test (pull_request) Failing after 4m18s

The speaker and the voice-fetch landed in the previous commit. This is the
remainder of the 939-line Swift program, ported, and the line it draws is
between DEVICE and ARITHMETIC rather than between languages.

Two things stay realizers, because they are the two things El cannot express
as arithmetic: handing a buffer to the DAC and waiting for it to drain
(el_audio_darwin.m), and asking the OS for samples off a mic or frames off a
camera (el_capture_darwin.m). Both are their own translation units declared
in el_runtime.h, never patches to el_runtime.c.

Everything else is El. WAV decode, LPC autocorrelation, Levinson-Durbin at
order 16, formant extraction off the all-pole envelope, source-filter
resynthesis, and the three descriptors are organ_dsp.el. Consent, disclosure
and the scene descriptor are organ.el. Barge-in, yield-or-hold, backchannel
and resume are organ_converse.el.

The organ never learns a word. Codes and phoneme geometry arrive from the
language side; the organ turns them into samples and gets the samples out the
speaker, and runs the same trip in reverse for the senses. No lexicon, no
grapheme-to-phoneme, by design.

Barge-in needed pause/resume and a real DAC position rather than a tick
counter, because "finish the buffer" is not barge-in and a queue holding
three buffers is a third of a second wrong about where it is. An injected
barge also had to fire once rather than stay true, which is otherwise a
livelock the moment a backchannel resumes.

Measured against the Swift on out/mic_room.wav: seconds, rms, peak, zcr,
centroid and F0 agree to every printed digit; formants F1-F5 and bandwidths
B1-B5 are identical. imitate cannot match bit-for-bit because the Swift
excites unvoiced frames with Double.random — two Swift runs correlate 0.957
with each other and El correlates 0.958 with Swift, so the port is as close
to the original as the original is to itself.

Verified end to end: consent fails closed on both locks, real mic capture
(16000 frames), real camera frame (1920x1080 -> 15 numbers), voiceprint,
imitate, hear-imitate, a voice learned by ear and fetched back out of the
engram, and all five converse paths with real audio. The binary contains
zero afplay/Swift strings and spawns no child process while speaking.
This commit is contained in:
Neuron
2026-08-16 16:42:41 -05:00
parent 5503e1d9a4
commit c26b6aac82
10 changed files with 2530 additions and 64 deletions
+195 -3
View File
@@ -333,12 +333,204 @@ fn organ_voice_ingest(name: String, f0: Int, f0_end: Int, kf: Int, f1: Int, f2:
// Turn the fetched geometry into the voice slot-map the render consumes. Kept
// separate from the fetch so the organ never invents a voice: if the fetch came
// back empty this returns empty too, and the caller has to deal with it.
//
// The slot-map is built here rather than by calling the render's own
// constructor, so the organ carries NO dependency on the language faculty's
// modules it only has to agree with them about a wire format, which is the
// looser and more honest coupling. (The layout is the same key/value [String]
// convention lang_get / surface_get / voice_get all read.)
fn organ_voice_profile(name: String, g: [Int]) -> [String] {
let empty: [String] = native_list_empty()
let r: [String] = native_list_empty()
if native_list_len(g) < 6 {
return empty
return r
}
return voice_new(name, native_list_get(g, 0), native_list_get(g, 1), native_list_get(g, 2), 1000, 1000, 8)
r = native_list_append(r, "name")
r = native_list_append(r, name)
r = native_list_append(r, "f0")
r = native_list_append(r, int_to_str(native_list_get(g, 0)))
r = native_list_append(r, "f0_end")
r = native_list_append(r, int_to_str(native_list_get(g, 1)))
r = native_list_append(r, "kf")
r = native_list_append(r, int_to_str(native_list_get(g, 2)))
r = native_list_append(r, "dur")
r = native_list_append(r, "1000")
r = native_list_append(r, "tilt")
r = native_list_append(r, "1000")
r = native_list_append(r, "breath")
r = native_list_append(r, "8")
return r
}
// Scene geometry (afferent, camera)
//
// The image half of the afferent metabolism, and the same principle as the
// audio descriptor: a frame is never handed on raw. The realizer returns a
// small pixel grid; THIS computes the descriptor, in El, because averaging
// pixels is arithmetic and arithmetic is not a device concern.
//
// Returns 15 numbers [w, h, meanR, meanG, meanB, brightness_pm, and a 3x3
// luminance grid] standing in for a multi-megapixel frame. The 3x3 grid is
// the smallest thing that still says WHERE the light is, which is most of what
// makes a scene comparable to another scene; a single brightness average would
// make a lamp on the left indistinguishable from a lamp on the right.
//
// Luminance is Rec. 601 (0.299R + 0.587G + 0.114B), in integer per-mille, so
// the descriptor is reproducible rather than subject to float drift.
fn organ_image_descriptor() -> [Int] {
let out: [Int] = native_list_empty()
let frame: Any = camera_capture_rgb()
if frame == 0 {
return out
}
let w: Int = el_map_get(frame, "width")
let h: Int = el_map_get(frame, "height")
let gw: Int = el_map_get(frame, "grid_w")
let gh: Int = el_map_get(frame, "grid_h")
let px: [Int] = el_map_get(frame, "pixels")
let np: Int = native_list_len(px)
if np < 3 {
return out
}
let count: Int = np / 3
let rsum: Int = 0
let gsum: Int = 0
let bsum: Int = 0
// 3x3 accumulators, row-major
let cell: [Int] = native_list_empty()
let cn: [Int] = native_list_empty()
let z: Int = 0
while z < 9 {
cell = native_list_append(cell, 0)
cn = native_list_append(cn, 0)
z = z + 1
}
// El has no list-set, so the cells are summed into parallel scalars and
// reassembled nine explicit accumulators would be worse to read than one
// pass per cell over a grid this small.
let c0: Int = 0
let c1: Int = 0
let c2: Int = 0
let c3: Int = 0
let c4: Int = 0
let c5: Int = 0
let c6: Int = 0
let c7: Int = 0
let c8: Int = 0
let n0: Int = 0
let n1: Int = 0
let n2: Int = 0
let n3: Int = 0
let n4: Int = 0
let n5: Int = 0
let n6: Int = 0
let n7: Int = 0
let n8: Int = 0
let i: Int = 0
while i < count {
let r: Int = native_list_get(px, i * 3)
let g: Int = native_list_get(px, i * 3 + 1)
let b: Int = native_list_get(px, i * 3 + 2)
rsum = rsum + r
gsum = gsum + g
bsum = bsum + b
let lum: Int = (299 * r + 587 * g + 114 * b) / 1000
let x: Int = i - (i / gw) * gw
let y: Int = i / gw
let cx: Int = x * 3 / gw
let cy: Int = y * 3 / gh
if cx > 2 {
cx = 2
}
if cy > 2 {
cy = 2
}
let idx: Int = cy * 3 + cx
if idx == 0 {
c0 = c0 + lum
n0 = n0 + 1
}
if idx == 1 {
c1 = c1 + lum
n1 = n1 + 1
}
if idx == 2 {
c2 = c2 + lum
n2 = n2 + 1
}
if idx == 3 {
c3 = c3 + lum
n3 = n3 + 1
}
if idx == 4 {
c4 = c4 + lum
n4 = n4 + 1
}
if idx == 5 {
c5 = c5 + lum
n5 = n5 + 1
}
if idx == 6 {
c6 = c6 + lum
n6 = n6 + 1
}
if idx == 7 {
c7 = c7 + lum
n7 = n7 + 1
}
if idx == 8 {
c8 = c8 + lum
n8 = n8 + 1
}
i = i + 1
}
let rA: Int = rsum / count
let gA: Int = gsum / count
let bA: Int = bsum / count
let bright: Int = (299 * rA + 587 * gA + 114 * bA) / 255
out = native_list_append(out, w)
out = native_list_append(out, h)
out = native_list_append(out, rA)
out = native_list_append(out, gA)
out = native_list_append(out, bA)
out = native_list_append(out, bright)
if n0 < 1 {
n0 = 1
}
if n1 < 1 {
n1 = 1
}
if n2 < 1 {
n2 = 1
}
if n3 < 1 {
n3 = 1
}
if n4 < 1 {
n4 = 1
}
if n5 < 1 {
n5 = 1
}
if n6 < 1 {
n6 = 1
}
if n7 < 1 {
n7 = 1
}
if n8 < 1 {
n8 = 1
}
out = native_list_append(out, c0 / n0)
out = native_list_append(out, c1 / n1)
out = native_list_append(out, c2 / n2)
out = native_list_append(out, c3 / n3)
out = native_list_append(out, c4 / n4)
out = native_list_append(out, c5 / n5)
out = native_list_append(out, c6 / n6)
out = native_list_append(out, c7 / n7)
out = native_list_append(out, c8 / n8)
organ_disclose("FEAT(image): 15-number scene-geometry vs " + int_to_str(w * h * 3) + " pixel-channels — the descriptor travels, the frame does not.")
return out
}
// Own-core tone