/// Append Holmes-elements for phones in (phonestr) to (eltq). /// Returns ps->t. unsigned phone_to_elm(phtoelm_state_t *ps, char *phonestr, dsqueue_t *eltq) { #ifdef PHOLMES_DEBUG post("phone_to_elm(): called with phonestr='%s'", phonestr); #endif ps->s = phonestr; while (ps->s && *ps->s) { pte_eltseq_str es = trie_lookup(&phtoelm, &(ps->s)); if (es) { int n = *es++; while (n-- > 0) { int eid = *es++; // -- index of sequence-element in Elements[] holmes_qelt_t he; // -- encoded Holmes-triple for output-queue Elm_ptr ep = &Elements[eid]; // -- pointer to actual current element int dur; // -- placeholder for element duration // // This works because only vowels have ud != du, // and we set stress just before a vowel // if (!(ep->feat & vwl)) ps->stress = 0; dur = StressDur(ep,ps->stress); he = hqeNew(eid,dur,ps->stress); // append the encoded element to the output queue dsqueue_append(eltq, (void *)he); #ifdef PHOLMES_DEBUG post("phone_to_elm(): enqueued Holmes-triple %s,%d,%d", ep->name,dur,ps->stress); #endif } } else { char ch = *(ps->s++); switch (ch) { case '\'': // Primary stress ps->stress = 3; break; case ',': // Secondary stress ps->stress = 2; break; case '+': // Tertiary stress ps->stress = 1; break; case '-': // hyphen in input break; case '.': // literal dot indicates end-of-utterance dsqueue_append(eltq, (void *)hqeNew(0,0,0)); break; default: { fprintf(stderr, "phone_to_elm(): ignoring unknown character '%c'\n", ch); break; } } } } return ps->t; }
static unsigned phone_to_elm(rsynth_t * rsynth, int n, char *phone, darray_ptr elm, darray_ptr f0) { float F0Hz = rsynth->speaker->F0Hz; float speed = rsynth->speed; int stress = 0; int seen_vowel = 0; int islong = 0; char *s = phone; unsigned t = 0; unsigned f0t = 0; char *limit = s + n; float f = darray_float(f0, F0Hz * 1.1F); if (!phtoelm) enter_phonemes(); while (s < limit && *s) { char *e = (char *) trie_lookup(&phtoelm, &s); if (e) { int n = *e++; while (n-- > 0) { int x = *e++; Elm_ptr p = &Elements[x]; darray_append(elm, x); /* StressDur works because only vowels have ud != du, and we set stress just before a vowel */ t += darray_append(elm, (int) (StressDur(p, stress, islong))); if (p->feat & vwl) { seen_vowel = 1; } else if (seen_vowel) { stress = 0; } } } else { char ch = *s++; switch (ch) { case '\'': /* Primary stress */ stress++; case ',': /* Secondary stress */ stress++; case '+': /* Tertiary stress */ stress++; if (stress > 3) stress = 3; seen_vowel = 0; /* f0 has been declining since f0t */ f = decline_f0(F0Hz, f0, f, t - f0t); f0t = t; /* Now stress pulse pushes f0 up "instantly" */ darray_float(f0, 0); darray_float(f0, f + F0Hz * stress * 0.02); break; case '-': /* hyphen in input */ break; case ':': /* Length mark */ islong = 1; break; default: fprintf(stderr, "Ignoring %c in '%.*s'\n", ch, n, phone); break; } } } /* Add final decline to f0 contour */ decline_f0(F0Hz, f0, f, t - f0t); return t; }