There is a third calling convention into Na_VoiceSe that skips
the phonology engine entirely, and it explains what a third of the voice samples are
for.
The text editor overlay — used for letters, town and player names, patterns, and
anywhere else the player types — speaks each keystroke from
src/game/m_editor_ovl.c:712:
if (command == mED_COMMAND_OUTPUT_CODE) {
int voice = mMsg_sound_voice_get_for_editor(editor_ovl->now_code);
if (voice == 0x85 || voice == 0x80 || voice == 0x81 ||
voice == 0x82 || voice == 0x83 || voice == -1)
voice = 0x86;
sAdo_VoiceSe(voice, 0xFF, 0xFF, 0, 32, 1); // ← mode 1
}
else if (command == mED_COMMAND_EXCHANGE_CODE) { // cursor moved onto a character
if (exchange_code != -1 && mED_exchange_se_list[exchange_code])
sAdo_VoiceSe(mMsg_sound_voice_get_for_editor(exchange_code), 0xFF, 0xFF, 0, 32, 1);
else
sAdo_SysTrgStart(0x36);
}
After both filters, only three things survive: letters (0x5D–0x76),
digits (0x53–0x5C), and the click (0x86).
Na_VoiceSe's two switch (f) blocks handle only cases 0 and 2.
With f == 1 both fall through, so:
sou_num_org etc. are never written, so sou_last_num =
sou_num_org further down just rewrites stale values — the message-path
history is not corrupted, but it is not updated either;r28 is left uninitialised and never read;Sou_SpecialRoutine10;a arrives at the playback stage as the raw voice code.The editor always runs at spec 5 or 6 (see gating), which
routes 0x86 to NA_SE_BEBE and passes everything else through. The
final guard is if (a != 0 && a <= 0x77), and letters and digits both
satisfy it. So:
typing 'a' → Sou_VoiceStart(subtrack, 0x5D) → instrument 0x5C typing 'z' → Sou_VoiceStart(subtrack, 0x76) → instrument 0x75 typing '0' → Sou_VoiceStart(subtrack, 0x53) → instrument 0x52
Trace the reachable phoneme codes across the whole engine:
| Code range | Instruments | Reached by |
|---|---|---|
0x01–0x52 | 0–81 | the phonology engine — short/long vowels, consonants, all 52 two-character digraphs plus you |
0x01–0x40 | also the anti-repetition random substitution (rand() >> 2) | |
0x53–0x76 | 82–117 | only mode 1 — one entry per digit and letter, in order |
0x77 | 118 | the you digraph, and nothing else |
The 0x53–0x76 block is exactly 36 codes: ten digits then
twenty-six letters, in the same order as the voice-code alphabet, and it is
unreachable through any dialogue. The obvious reading is that these 36 samples are the
spoken names of the digits and letters — what you hear when typing a name
one character at a time.
Spec 3 (Wendell, Pete, Booker, Jack) uses sequence 244 / bank 157, which has 83
instruments — codes 0x01–0x53. That covers the entire phonology
output range (≤ 0x52) with one to spare, and omits the letter-name block
that spec 3 can never reach, since the editor is always spec 5 or 6.
The one real casualty is you (0x77): the sequence's dynamic
table clamps out-of-range entries to the last routine, so a spec-3 voice saying "you"
plays instrument 82 instead. That is one wrong syllable on a common word, in four
NPCs' voices.
extraction.md §2.4, which described bank 157
as "collapsing every digraph sample above 0x53 onto one sound". Nothing above
0x53 is a digraph — the block is not phonology at all.