Files
el/lang/runtime/el_peripheral_null.c
T
Neuron 5503e1d9a4 organ: el gets a speaker, and fetches the voice from the engram
El could turn meaning into samples and could not make a sound. Every path
from those samples to the air ran outside the language, through a 939-line
Swift program that shelled out to afplay, so the voice was not a capability
of El or of Neuron but a separate binary standing next to them.

Two things land here.

The speaker. el_audio_darwin.m is a CoreAudio AudioQueue realizer in its own
translation unit, declared in el_runtime.h, deliberately not a patch to
el_runtime.c — acquiring a device must not mean editing the middle of the
language, the same rule the realizer registry follows for modalities. It
takes samples straight out of memory, so nothing is written to disk and no
process is spawned between the intent to speak and the sound. The async half
(play/stop/playing/played_frames) exists because barge-in means stopping on
the spot, and a blocking play cannot be interrupted. el_peripheral_null.c is
the same entry points everywhere else, so El that speaks links anywhere and
truthfully reports having no speaker.

The voice. organ_voice_fetch asks the engram for a voice region by query and
reads the geometry off the node that comes back. A voice is not a JSON file
next to the code; it is a memory, and the organ retrieves it the way anything
retrieves a memory. An absent region returns empty rather than a plausible
default, because a caller must be able to tell 'this is how they sound' from
'I never heard them'.

Underneath both: __str_set_char bounds-checked writes against strlen(), which
is 0 for the zero-filled buffer __str_alloc hands back, so every write was
rejected and every El-authored WAV in this repo was 55,244 bytes of silence
that reported ok=true. Byte buffers now carry their capacity in a side table;
text keeps the exact strlen behaviour it had. This is why nobody noticed El
was mute.

Measured: voice fetched from the engram reads f0=137 f0_end=116 kf=1269
f1=500 f2=2093 f3=3531, matching the 30s LPC measurement; render is 20160
samples at 16 kHz; both the rendered utterance and an own-core tone played
aloud through CoreAudio with no Swift and no afplay in the chain.
2026-08-16 16:27:30 -05:00

77 lines
3.3 KiB
C

/* el_peripheral_null.c — the no-device build of El's I/O organ.
*
* Every entry point declared in el_runtime.h's "Peripheral" block, implemented
* as an honest refusal. This is what a platform without an El audio/capture
* realizer links instead of el_audio_darwin.m + el_capture_darwin.m, so an El
* program that speaks or listens still COMPILES AND LINKS everywhere.
*
* The distinction that matters: these do not pretend. speaker_available() and
* mic_available() return 0, and every operation returns its failure sentinel.
* A program asking "can I speak here?" gets a truthful no, rather than a
* silence it would have to infer something from. Silent success is the failure
* mode this whole change exists to eliminate — El spent this entire codebase's
* history writing WAV files full of zeros and reporting ok=true, and nobody
* caught it because nothing ever said "there is no sound here".
*
* Compiled INSTEAD OF the Darwin realizers, never alongside them — the symbols
* are the same by design, which is the point: the El side never branches on
* platform, it branches on speaker_available().
*/
#include "el_runtime.h"
#if !defined(__APPLE__)
/* ── Speaker ─────────────────────────────────────────────────────────────── */
el_val_t speaker_available(void) { return (el_val_t)0; }
el_val_t speaker_name(void) { return EL_STR("none"); }
el_val_t speaker_play_pcm16(el_val_t samples, el_val_t sample_rate) {
(void)samples; (void)sample_rate;
return (el_val_t)0;
}
el_val_t speaker_play_wav(el_val_t path) {
(void)path;
return (el_val_t)0;
}
el_val_t speaker_play_pcm16_async(el_val_t samples, el_val_t sample_rate) {
(void)samples; (void)sample_rate;
return (el_val_t)0;
}
el_val_t speaker_playing(void) { return (el_val_t)0; }
el_val_t speaker_stop(void) { return (el_val_t)0; }
el_val_t speaker_played_frames(void) { return (el_val_t)0; }
/* ── Microphone ──────────────────────────────────────────────────────────── */
el_val_t mic_available(void) { return (el_val_t)0; }
el_val_t mic_request_access(void) { return (el_val_t)0; }
/* Empty list, not 0: the contract says capture returns samples, and a caller
* iterating the result must find nothing rather than dereference a non-list. */
el_val_t mic_capture_pcm16(el_val_t seconds, el_val_t sample_rate) {
(void)seconds; (void)sample_rate;
return el_list_empty();
}
el_val_t mic_monitor_start(void) { return (el_val_t)0; }
el_val_t mic_monitor_rms(void) { return el_from_float(0.0); }
el_val_t mic_monitor_stop(void) { return (el_val_t)0; }
/* ── Camera ──────────────────────────────────────────────────────────────── */
el_val_t camera_available(void) { return (el_val_t)0; }
el_val_t camera_request_access(void) { return (el_val_t)0; }
el_val_t camera_capture_rgb(void) { return (el_val_t)0; }
el_val_t camera_capture_jpeg(el_val_t path) {
(void)path;
return (el_val_t)0;
}
#endif /* !__APPLE__ */