the text to phoneme conversion

Overview

Aramacao employs two different ways for converting text into phonemes. The first way is to use a dictionary where every possible word is listed along the phonemes that make it: this method is currently used for the English language. The second way is to use some general rules to translate any given letter to a corresponding phoneme: this method is currently used for the Italian and Spanish languages.

The code

The relevant code for converting text into phonemes is in the file script_breakdown.c. All the functions defined in script_breakdown.c are called by functions defined in the script.c file.

These functions can be classified as follows:

Functions
Wrappers

these functions call the right functions to convert a given string of text into phonemes, given an integer input which identifies a chosen language

script_breakdown_line

this function is used when adding or editing a line of text

script_breakdown_word

this function is only used when editing a word

Utility

these are functions used for common tasks

script_breakdown_common

breaks a line into words and then uses a pointer to function for calling the right function to convert those words into phonemes, the pointer to function is passed from script_breakdown_line

script_breakdown_phoneme_init

this small function initializes a new phoneme

get_char

returns a character at a given position in a string

Converters

these functions can convert a given word of a certain language into phonemes

___breakdown_phoneme

when the laguage selected is "none" (0)

en_breakdown_phoneme

for the English language (1), this function uses a dictionary

it_breakdown_phoneme

for the Italian language (2)

es_breakdown_phoneme

for the Spanish language (3)

Visualization
   _______________________
  |                       |
  | script_breakdown_line |
  |_______________________|
              |
   ___________|_____________
  |                         |
  | script_breakdown_common |
  |___________._____________|
              :.....................................
   ___________:__________ : ___________:__________ :
  |                      |:|                      |:
  | ___breakdown_phoneme |:| it_breakdown_phoneme |:
  |______________________|:|______________________|:
       |                  :           |            :
       |       ___________:__________ | ___________:__________
       |      |                      |||                      |
       |      | en_breakdown_phoneme ||| es_breakdown_phoneme |
       |      |______________________|||______________________|
       |           |                  |     |
       |           |                  |     |
   ____|___________|______________    |     |
  |                               |---|     |
  | script_breakdown_phoneme_init |   |     |
  |_______________________________|---+-----|
                                      |     |
                                      |    _|________
                                      |   |          |
                                      '---| get_char |
                                          |__________|

The phoneme set

Aramacao internally uses the phoneme set of the Carnegie Mellon University Pronouncing Dictionary. So the phoneme names are the same as those used by the CMU Pronouncing Dictionary. An extra phoneme (STOP) was added, it is a mute (rest position) phoneme.

Phoneme Example Translation IPA
------- ------- ----------- ---
AA      odd     AA D         ɒ
AE      at      AE T         æ
AH      hut     HH AH T      ʌ
AO      ought   AO T         ɑ
AW      cow     K AW         aʊ
AY      hide    HH AY D      aɪ
B       be      B IY         b
CH      cheese  CH IY Z      tʃ
D       dee     D IY         d
DH      thee    DH IY        ð
EH      Ed      EH D         e
ER      hurt    HH ER T      ɜ
EY      ate     EY T         eɪ
F       fee     F IY         f
G       green   G R IY N     g
HH      he      HH IY        h
IH      it      IH T         ɪ
IY      eat     IY T         i
JH      gee     JH IY        dʒ
K       key     K IY         k
L       lee     L IY         l
M       me      M IY         m
N       knee    N IY         n
NG      ping    P IH NG      ŋ
OW      oat     OW T         oʊ
OY      toy     T OY         ɔɪ
P       pee     P IY         p
R       read    R IY D       r
S       sea     S IY         s
SH      she     SH IY        ʃ
T       tea     T IY         t
TH      theta   TH EY T AH   θ
UH      hood    HH UH D      ʊ
UW      two     T UW         u
V       vee     V IY         v
W       we      W IY         w
Y       yield   Y IY L D     j
Z       zee     Z IY         z
ZH      seizure S IY ZH ER   ʒ

STOP    rest position (no sound)
Caution The CMU Pronouncing Dictionary refers to the American English pronunciation.

Dictionary based conversion

The function script_breakdown_common calls the function used to convert a word into phonemes using as arguments: a file handler (for the dictionary file), a pointer to the first character of the word, a pointer to the last character (\0) and a pointer to a Word struct.

An excerpt of the CMU dictionary:

APPRECIATION  AH0 P R IY2 SH IY0 EY1 SH AH0 N
APPRECIATIVE  AH0 P R IY1 SH IY0 EY2 T IH0 V
APPRECIATIVELY  AH0 P R IY1 SH IY0 EY2 T IH0 V L IY0
APPREHEND  AE2 P R AH0 HH EH1 N D

The en_breakdown_phoneme function has to: strip punctuation characters (e.g. apples → apples), convert all the characters to uppercase (apples → APPLES), cycle through all the entries of the dictionary and finally extract the phonemes.

It calls script_breakdown_phoneme_init to initialize the phoneme.

If a word is not found in the dictionary, every characters of that word is converted in a "rest position" phoneme. It may be a foreign word or an onomatopoeic word: those words can be manually edited later.

Rules based conversion

The function script_breakdown_common calls the function used to convert a word into phonemes with the arguments: a NULL file handler (for the unused dictionary file), a pointer to the first character of the word, a pointer to the last character (\0) and a pointer to a Word struct.

The it_breakdown_phoneme function has to: cycle through all the characters of the given word, usually ignore non-letter characters, translate those characters into corresponding phonemes.

Since the phonemic value of a letter may depend on the following letters, the function get_char is used to retrieve one or more characters from the string to assign the correct phonemic value.

E.g.: mute letter, no phoneme assigned
switch (get_char(copy->str, i)) {
...
  case 'h':
    break;
...
}
E.g.: simple case, the letter corresponds always to the same phoneme
switch (get_char(copy->str, i)) {
...
  case 'd':
    p = D;
    break;
...
}
E.g.: still a simple case, one letter, two phonemes
switch (get_char(copy->str, i)) {
...
  case 'x':
    p = K;
    p_1 = S;
    break;
...
}
E.g.: more complex case, the phonemic value depends on the following letters
switch (get_char(copy->str, i)) {
...
  case 'c':
    switch (get_char(copy->str, i+1)) {
      case 'i':
        switch (get_char(copy->str, i+2)) {
          case 'i':
          case 172: /* ì - non esiste */
          case 'e':
          case 168:
          case 169:
          case 'o':
          case 178:
          case 179:
          case 'u':
          case 185:
          case 'a':
          case 160:
          case 161:
            i++;
          default:
            p = CH;
            break;
        }
        break;
      case 172: /* ì */
      case 'e':
      case 168: /* è */
      case 169: /* é */
        p = CH;
        break;
      default:
        p = K;
        break;
    }
    break;
...
}

Once the phoneme is determined it calls script_breakdown_phoneme_init to initialize said phoneme.

Example

Or: how the "none" language was added.

Creating a function for conversion

The "none" language simply convert every character of a word into a "rest" (STOP) phoneme.

The code is therefore very simple.

___breakdown_phoneme
void ___breakdown_phoneme(FILE *fp, guchar *ap, guchar *bp, Word *word)
{
  guint i;

  for (i = 0; i < bp - ap; i++) {
    Phoneme *phoneme = script_breakdown_phoneme_init(STOP);
    word->phonemes = g_slist_append(word->phonemes, phoneme);
  }
}

This function must be added to the script_breakdown.c file, including a function prototype at the beginning of the file.

void ___breakdown_phoneme(FILE *, guchar *, guchar *, Word *);

Adding the conversion function to the list

At the beginning of the script_breakdown.c file there is a list of function pointers called LANG_FUNC_LIST. You have to add your newly created function at the end of the list:

void (* LANG_FUNC_LIST[]) (FILE *, guchar *, guchar *, Word *) = {
  ...
  ___breakdown_phoneme,
};

Adding a dictionary file

Even if your function does not use a dictionary, you have to add one to the list LANG_DIC_LIST. Since ___breakdown_phoneme does not need a dictionary, it suffices to add an empty string at the end of the list:

gchar * LANG_DIC_LIST[] = {
  ...
  "",
};

If otherwise your function need a dictionary, you have to add the name of the dictionary file, e.g. "EN_dictionary.txt".

Aramacao will search for that file in its dic directory.

Caution You may need to add your dictionary to the aramacaodic_DATA array located in Makefile.am if you want to install it through make install.

Adding your language to the list of supported languages

Now you have to search for the script_lang_list function in the script.c file. It is the first one.

You have to add your language name to the LANG_LIST list:

gchar * script_lang_list(gint k)
{
  gchar * LANG_LIST[] = {
    ...
    _("none"),
  ""};

  gchar * ret = malloc(sizeof(LANG_LIST[k]));
  strcpy(ret, LANG_LIST[k]);

  return ret;
}