Files
babbler/examples/example_names.c
2026-01-28 22:20:52 +01:00

178 lines
6.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* EXAMPLE: Structured Name Generation (The "Brain")
*
* Unlike the random motor babbler, this program applies high-level linguistic
* constraints to the articulatory physics engine. It defines specific phoneme
* subsets (Languages) and grammar rules (Syllable Structure) to guide the mouth.
*
* It demonstrates that by constraining the chaos of the physics engine with
* simple rules (Attractor States), we can generate distinct, recognizable
* "accents" or "languages".
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "articulator.h"
#include "transcriber.h"
extern char RAW_OUTPUT_BUFFER[];
extern const phoneme_t PHONEME_DB[];
extern const ortho_rule_t ORTHO_IPA[];
extern const ortho_rule_t ORTHO_POLISH[];
extern const ortho_rule_t ORTHO_HUNGARIAN[];
extern const ortho_rule_t ORTHO_GERMAN[];
extern const ortho_rule_t ORTHO_CYRILLIC[];
extern const ortho_rule_t ORTHO_ORCISH[];
/* --- LANGUAGE DEFINITIONS --- */
/* Standard Fantasy/English-ish */
const char* LANG_COMMON[] = {"p", "b", "t", "d", "k", "g", "m", "n", "f", "v", "s", "z", "ʃ", "h", "r",
"l", "w", "j", "i", "u", "e", "o", "a", "ə", "ɪ", "ɛ", "æ", "ɔ", NULL};
const char* LANG_SLAVIC[] = {
// Vowels (Simple 6 system)
"i", "u", "e", "o", "a", "ɨ", // ɨ is Polish 'y'
// Consonants
"p", "b", "t", "d", "k", "g", "m", "n", "ɲ", // n, ń
"f", "v", "s", "z", "x", // f, w, s, z, ch
"ts", "dz", // c, dz
"ʃ", "ʒ", "", "", // sz, ż, cz, dż
"ɕ", "ʑ", "", "", // ś, ź, ć, dź
"l", "r", "j", "w", // l, r, j, ł
NULL};
/* Harsh/Orcish (Back of throat, Guttural) */
const char* LANG_ORCISH[] = {"k", "g", "q", "ɢ", "ʔ", "x", "χ", "ʁ", "h", "p", "b", "t", "d", "u", "o", "ɑ", "ɔ", NULL};
/* Soft/Elvish (Liquids, Fricatives, Front Vowels) */
const char* LANG_ELVISH[] = {"p", "b", "t", "d", "m", "n", "f", "v", "s", "z", "ʃ", "ʒ", "θ", "ð",
"l", "ʎ", "r", "w", "j", "i", "y", "e", "ø", "a", "ɛ", "œ", NULL};
/* --- FILTER HELPER --- */
/* Check if an IPA symbol exists in the allowed list */
int is_allowed(const char* ipa, const char** allowed_list) {
for (int i = 0; allowed_list[i] != NULL; i++) {
if (strcmp(ipa, allowed_list[i]) == 0) return 1;
}
return 0;
}
/* --- UPDATED GENERATOR --- */
void generate_name(const char* race_name, const char** allowed_sounds, int syllables) {
printf("\n=== Generating %s Name (%d syl) ===\n", race_name, syllables);
// 1. Build Index Cache for this Language
int v_indices[100], v_count = 0;
int c_indices[100], c_count = 0;
for (int i = 0; PHONEME_DB[i].ipa != NULL; i++) {
// Only add if it's in the allowed list
if (is_allowed(PHONEME_DB[i].ipa, allowed_sounds)) {
if (is_vowel_index(i)) {
if (v_count < 100) v_indices[v_count++] = i;
} else {
if (c_count < 100) c_indices[c_count++] = i;
}
}
}
if (v_count == 0 || c_count == 0) {
printf("Error: No sounds found for %s\n", race_name);
return;
}
// 2. Build Sequence (C-V-C pattern)
int len = 0;
int seq[100];
for (int s = 0; s < syllables; s++) {
// Onset
if (rand() % 10 < 7) seq[len++] = c_indices[rand() % c_count];
// Nucleus
seq[len++] = v_indices[rand() % v_count];
// Coda
if (rand() % 10 < 4) seq[len++] = c_indices[rand() % c_count];
}
// 3. Simulate & Transcribe
simulate_sequence(seq, len);
}
int main(void) {
srand(time(NULL));
char word[256];
for (int i = 0; i < 3; i++) {
generate_name("Human", LANG_COMMON, 2 + i);
printf("RAW: \"%s\"\n", RAW_OUTPUT_BUFFER);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_IPA);
printf("IPA: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_POLISH);
printf(" PL: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_HUNGARIAN);
printf(" HU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_GERMAN);
printf(" DE: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_CYRILLIC);
printf(" RU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_ORCISH);
printf("ORC: \"%s\"\n", word);
}
for (int i = 0; i < 3; i++) {
generate_name("Slavic", LANG_SLAVIC, 2 + i);
printf("RAW: \"%s\"\n", RAW_OUTPUT_BUFFER);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_IPA);
printf("IPA: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_POLISH);
printf(" PL: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_HUNGARIAN);
printf(" HU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_GERMAN);
printf(" DE: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_CYRILLIC);
printf(" RU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_ORCISH);
printf("ORC: \"%s\"\n", word);
}
for (int i = 0; i < 3; i++) {
generate_name("Orcish", LANG_ORCISH, 2 + i);
printf("RAW: \"%s\"\n", RAW_OUTPUT_BUFFER);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_IPA);
printf("IPA: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_POLISH);
printf(" PL: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_HUNGARIAN);
printf(" HU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_GERMAN);
printf(" DE: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_CYRILLIC);
printf(" RU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_ORCISH);
printf("ORC: \"%s\"\n", word);
}
for (int i = 0; i < 3; i++) {
generate_name("Elvish", LANG_ELVISH, 2 + i);
printf("RAW: \"%s\"\n", RAW_OUTPUT_BUFFER);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_IPA);
printf("IPA: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_POLISH);
printf(" PL: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_HUNGARIAN);
printf(" HU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_GERMAN);
printf(" DE: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_CYRILLIC);
printf(" RU: \"%s\"\n", word);
transcribe(RAW_OUTPUT_BUFFER, word, ORTHO_ORCISH);
printf("ORC: \"%s\"\n", word);
}
return 0;
}