if (plist == NULL) | if (plist == NULL) | ||||
InterpretPhoneme2(ph->code, &phdata); | InterpretPhoneme2(ph->code, &phdata); | ||||
else | else | ||||
InterpretPhoneme(NULL, 0, plist, &phdata, NULL); | |||||
InterpretPhoneme(NULL, 0, plist, plist, &phdata, NULL); | |||||
p = phdata.ipa_string; | p = phdata.ipa_string; | ||||
if (*p == 0x20) { | if (*p == 0x20) { |
#include "speech.h" | #include "speech.h" | ||||
static void SetRegressiveVoicing(int regression, PHONEME_LIST2 *plist2, PHONEME_TAB *ph, Translator *tr); | static void SetRegressiveVoicing(int regression, PHONEME_LIST2 *plist2, PHONEME_TAB *ph, Translator *tr); | ||||
static void ReInterpretPhoneme(PHONEME_TAB *ph, PHONEME_TAB *ph2, PHONEME_LIST *plist3, Translator *tr, PHONEME_DATA *phdata, WORD_PH_DATA *worddata); | |||||
static void ReInterpretPhoneme(PHONEME_TAB *ph, PHONEME_TAB *ph2, PHONEME_LIST *plist3, PHONEME_LIST *plist3_start, Translator *tr, PHONEME_DATA *phdata, WORD_PH_DATA *worddata); | |||||
static const unsigned char pause_phonemes[8] = { | static const unsigned char pause_phonemes[8] = { | ||||
0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG | 0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG | ||||
if (ph == NULL) continue; | if (ph == NULL) continue; | ||||
InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata); | |||||
InterpretPhoneme(tr, 0x100, plist3, ph_list3, &phdata, &worddata); | |||||
if ((alternative = phdata.pd_param[pd_CHANGE_NEXTPHONEME]) > 0) { | if ((alternative = phdata.pd_param[pd_CHANGE_NEXTPHONEME]) > 0) { | ||||
ph_list3[j+1].ph = phoneme_tab[alternative]; | ph_list3[j+1].ph = phoneme_tab[alternative]; | ||||
plist3->ph = ph; | plist3->ph = ph; | ||||
plist3->phcode = alternative; | plist3->phcode = alternative; | ||||
ReInterpretPhoneme(ph, ph2, plist3, tr, &phdata, &worddata); | |||||
ReInterpretPhoneme(ph, ph2, plist3, ph_list3, tr, &phdata, &worddata); | |||||
} | } | ||||
if ((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0) { | if ((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0) { | ||||
if (alternative == 1) | if (alternative == 1) | ||||
deleted = true; // NULL phoneme, discard | deleted = true; // NULL phoneme, discard | ||||
else { | else { | ||||
ReInterpretPhoneme(ph, ph2, plist3, tr, &phdata, &worddata); | |||||
ReInterpretPhoneme(ph, ph2, plist3, ph_list3, tr, &phdata, &worddata); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void ReInterpretPhoneme(PHONEME_TAB *ph, PHONEME_TAB *ph2, PHONEME_LIST *plist3, Translator *tr, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) { | |||||
static void ReInterpretPhoneme(PHONEME_TAB *ph, PHONEME_TAB *ph2, PHONEME_LIST *plist3, PHONEME_LIST *plist3_start, Translator *tr, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) { | |||||
if (ph->type == phVOWEL) { | if (ph->type == phVOWEL) { | ||||
plist3->synthflags |= SFLAG_SYLLABLE; | plist3->synthflags |= SFLAG_SYLLABLE; | ||||
if (ph2->type != phVOWEL) | if (ph2->type != phVOWEL) | ||||
// re-interpret the changed phoneme | // re-interpret the changed phoneme | ||||
// But it doesn't obey a second ChangePhoneme() | // But it doesn't obey a second ChangePhoneme() | ||||
InterpretPhoneme(tr, 0x100, plist3, phdata, worddata); | |||||
InterpretPhoneme(tr, 0x100, plist3, plist3_start, phdata, worddata); | |||||
} | } |
if (released == false) | if (released == false) | ||||
p->synthflags |= SFLAG_NEXT_PAUSE; | p->synthflags |= SFLAG_NEXT_PAUSE; | ||||
InterpretPhoneme(NULL, 0, p, &phdata, NULL); | |||||
InterpretPhoneme(NULL, 0, p, plist, &phdata, NULL); | |||||
len = DoSample3(&phdata, 0, -1); | len = DoSample3(&phdata, 0, -1); | ||||
len = (len * 1000)/samplerate; // convert to mS | len = (len * 1000)/samplerate; // convert to mS | ||||
break; | break; | ||||
case phFRICATIVE: | case phFRICATIVE: | ||||
len = 0; | len = 0; | ||||
InterpretPhoneme(NULL, 0, p, &phdata, NULL); | |||||
InterpretPhoneme(NULL, 0, p, plist, &phdata, NULL); | |||||
if (p->synthflags & SFLAG_LENGTHEN) | if (p->synthflags & SFLAG_LENGTHEN) | ||||
len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc. | len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc. | ||||
len += DoSample3(&phdata, p->length, -1); | len += DoSample3(&phdata, p->length, -1); | ||||
case phNASAL: | case phNASAL: | ||||
if (next->type != phVOWEL) { | if (next->type != phVOWEL) { | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
InterpretPhoneme(NULL, 0, p, &phdata, NULL); | |||||
InterpretPhoneme(NULL, 0, p, plist, &phdata, NULL); | |||||
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | ||||
len = DoSpect2(p->ph, 0, &fmtp, p, -1); | len = DoSpect2(p->ph, 0, &fmtp, p, -1); | ||||
len = (len * 1000)/samplerate; | len = (len * 1000)/samplerate; |
} | } | ||||
static int CountVowelPosition(PHONEME_LIST *plist) | |||||
static int CountVowelPosition(PHONEME_LIST *plist, PHONEME_LIST *plist_start) | |||||
{ | { | ||||
int count = 0; | int count = 0; | ||||
for (;;) { | for (;;) { | ||||
if (plist->ph->type == phVOWEL) | if (plist->ph->type == phVOWEL) | ||||
count++; | count++; | ||||
if (plist->sourceix != 0) | |||||
if (plist->sourceix != 0 || plist == plist_start) | |||||
break; | break; | ||||
plist--; | plist--; | ||||
} | } | ||||
return count; | return count; | ||||
} | } | ||||
static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, unsigned short *p_prog, WORD_PH_DATA *worddata) | |||||
static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_LIST *plist_start, unsigned short *p_prog, WORD_PH_DATA *worddata) | |||||
{ | { | ||||
unsigned int data; | unsigned int data; | ||||
int instn; | int instn; | ||||
{ | { | ||||
case 0: // prevPh | case 0: // prevPh | ||||
case 5: // prevPhW | case 5: // prevPhW | ||||
if (plist < plist_start+1) | |||||
return false; | |||||
plist--; | plist--; | ||||
check_endtype = true; | check_endtype = true; | ||||
break; | break; | ||||
plist = &plist[3]; | plist = &plist[3]; | ||||
break; | break; | ||||
case 10: // prev2PhW | case 10: // prev2PhW | ||||
if (plist < plist_start + 2) | |||||
return false; | |||||
if ((plist[0].sourceix) || (plist[-1].sourceix)) | if ((plist[0].sourceix) || (plist[-1].sourceix)) | ||||
return false; | return false; | ||||
plist -= 2; | plist -= 2; | ||||
if ((which == 0) || (which == 5)) { | if ((which == 0) || (which == 5)) { | ||||
if (plist->phcode == 1) { | if (plist->phcode == 1) { | ||||
if (plist <= plist_start) | |||||
return false; | |||||
// This is a NULL phoneme, a phoneme has been deleted so look at the previous phoneme | // This is a NULL phoneme, a phoneme has been deleted so look at the previous phoneme | ||||
plist--; | plist--; | ||||
} | } | ||||
if (plist->sourceix != 0) | if (plist->sourceix != 0) | ||||
return false; | return false; | ||||
do { | do { | ||||
if (plist <= plist_start) | |||||
return false; | |||||
plist--; | plist--; | ||||
if ((plist->stresslevel & 0xf) >= 4) | if ((plist->stresslevel & 0xf) >= 4) | ||||
return true; | return true; | ||||
case isVoiced: | case isVoiced: | ||||
return (ph->type == phVOWEL) || (ph->type == phLIQUID) || (ph->phflags & phVOICED); | return (ph->type == phVOWEL) || (ph->type == phLIQUID) || (ph->phflags & phVOICED); | ||||
case isFirstVowel: | case isFirstVowel: | ||||
return CountVowelPosition(plist) == 1; | |||||
return CountVowelPosition(plist, plist_start) == 1; | |||||
case isSecondVowel: | case isSecondVowel: | ||||
return CountVowelPosition(plist) == 2; | |||||
return CountVowelPosition(plist, plist_start) == 2; | |||||
case isTranslationGiven: | case isTranslationGiven: | ||||
return (plist->synthflags & SFLAG_DICTIONARY) != 0; | return (plist->synthflags & SFLAG_DICTIONARY) != 0; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) | |||||
void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_LIST *plist_start, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) | |||||
{ | { | ||||
// control: | // control: | ||||
// bit 0: PreVoicing | // bit 0: PreVoicing | ||||
truth = true; | truth = true; | ||||
while ((instn & 0xe000) == 0x2000) { | while ((instn & 0xe000) == 0x2000) { | ||||
// process a sequence of conditions, using boolean accumulator | // process a sequence of conditions, using boolean accumulator | ||||
truth2 = InterpretCondition(tr, control, plist, prog, worddata); | |||||
truth2 = InterpretCondition(tr, control, plist, plist_start, prog, worddata); | |||||
prog += NumInstnWords(prog); | prog += NumInstnWords(prog); | ||||
if (*prog == i_NOT) { | if (*prog == i_NOT) { | ||||
truth2 = truth2 ^ 1; | truth2 = truth2 ^ 1; | ||||
plist[1].ph = phoneme_tab[phcode]; | plist[1].ph = phoneme_tab[phcode]; | ||||
plist[2].sourceix = 1; | plist[2].sourceix = 1; | ||||
InterpretPhoneme(NULL, 0, &plist[1], phdata, NULL); | |||||
InterpretPhoneme(NULL, 0, &plist[1], plist, phdata, NULL); | |||||
} | } |
void InterpretPhoneme(Translator *tr, | void InterpretPhoneme(Translator *tr, | ||||
int control, | int control, | ||||
PHONEME_LIST *plist, | PHONEME_LIST *plist, | ||||
PHONEME_LIST *plist_start, | |||||
PHONEME_DATA *phdata, | PHONEME_DATA *phdata, | ||||
WORD_PH_DATA *worddata); | WORD_PH_DATA *worddata); | ||||
if (ph->phflags & phPREVOICE) { | if (ph->phflags & phPREVOICE) { | ||||
// a period of voicing before the release | // a period of voicing before the release | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
InterpretPhoneme(NULL, 0x01, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0x01, p, phoneme_list, &phdata, &worddata); | |||||
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | ||||
fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | ||||
DoSpect2(ph, 0, &fmtp, p, 0); | DoSpect2(ph, 0, &fmtp, p, 0); | ||||
} | } | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
phdata.pd_control |= pd_DONTLENGTHEN; | phdata.pd_control |= pd_DONTLENGTHEN; | ||||
DoSample3(&phdata, 0, 0); | DoSample3(&phdata, 0, 0); | ||||
break; | break; | ||||
case phFRICATIVE: | case phFRICATIVE: | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
if (p->synthflags & SFLAG_LENGTHEN) | if (p->synthflags & SFLAG_LENGTHEN) | ||||
DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc. | DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc. | ||||
if ((prev->type == phVOWEL) || (ph->phflags & phPREVOICE)) { | if ((prev->type == phVOWEL) || (ph->phflags & phPREVOICE)) { | ||||
// a period of voicing before the release | // a period of voicing before the release | ||||
InterpretPhoneme(NULL, 0x01, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0x01, p, phoneme_list, &phdata, &worddata); | |||||
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | ||||
fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | ||||
StartSyllable(); | StartSyllable(); | ||||
} else | } else | ||||
p->synthflags |= SFLAG_NEXT_PAUSE; | p->synthflags |= SFLAG_NEXT_PAUSE; | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | ||||
fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | ||||
fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV]; | fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV]; | ||||
StartSyllable(); | StartSyllable(); | ||||
else | else | ||||
p->synthflags |= SFLAG_NEXT_PAUSE; | p->synthflags |= SFLAG_NEXT_PAUSE; | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; | fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; | ||||
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | ||||
if (prev->type == phNASAL) | if (prev->type == phNASAL) | ||||
last_frame = NULL; | last_frame = NULL; | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; | fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2; | ||||
fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | fmtp.fmt_addr = phdata.sound_addr[pd_FMT]; | ||||
fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | fmtp.fmt_amp = phdata.sound_param[pd_FMT]; | ||||
if (next->type == phVOWEL) | if (next->type == phVOWEL) | ||||
StartSyllable(); | StartSyllable(); | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
if ((value = (phdata.pd_param[i_PAUSE_BEFORE] - p->prepause)) > 0) | if ((value = (phdata.pd_param[i_PAUSE_BEFORE] - p->prepause)) > 0) | ||||
DoPause(value, 1); | DoPause(value, 1); | ||||
memset(&fmtp, 0, sizeof(fmtp)); | memset(&fmtp, 0, sizeof(fmtp)); | ||||
InterpretPhoneme(NULL, 0, p, &phdata, &worddata); | |||||
InterpretPhoneme(NULL, 0, p, phoneme_list, &phdata, &worddata); | |||||
fmtp.std_length = phdata.pd_param[i_SET_LENGTH] * 2; | fmtp.std_length = phdata.pd_param[i_SET_LENGTH] * 2; | ||||
vowelstart_prev = 0; | vowelstart_prev = 0; | ||||
fmtp.fmt_length = phdata.sound_param[pd_VWLSTART]; | fmtp.fmt_length = phdata.sound_param[pd_VWLSTART]; | ||||
} else if (prev->type != phPAUSE) { | } else if (prev->type != phPAUSE) { | ||||
// check the previous phoneme | // check the previous phoneme | ||||
InterpretPhoneme(NULL, 0, prev, &phdata_prev, NULL); | |||||
InterpretPhoneme(NULL, 0, prev, phoneme_list, &phdata_prev, NULL); | |||||
if (((fmtp.fmt_addr = phdata_prev.sound_addr[pd_VWLSTART]) != 0) && (phdata_prev.pd_control & pd_FORNEXTPH)) { | if (((fmtp.fmt_addr = phdata_prev.sound_addr[pd_VWLSTART]) != 0) && (phdata_prev.pd_control & pd_FORNEXTPH)) { | ||||
// a vowel start has been specified by the previous phoneme | // a vowel start has been specified by the previous phoneme | ||||
vowelstart_prev = 1; | vowelstart_prev = 1; | ||||
fmtp.fmt2_lenadj = phdata.sound_param[pd_VWLEND]; | fmtp.fmt2_lenadj = phdata.sound_param[pd_VWLEND]; | ||||
else if (next->type != phPAUSE) { | else if (next->type != phPAUSE) { | ||||
fmtp.fmt2_lenadj = 0; | fmtp.fmt2_lenadj = 0; | ||||
InterpretPhoneme(NULL, 0, next, &phdata_next, NULL); | |||||
InterpretPhoneme(NULL, 0, next, phoneme_list, &phdata_next, NULL); | |||||
fmtp.use_vowelin = 1; | fmtp.use_vowelin = 1; | ||||
fmtp.transition0 = phdata_next.vowel_transition[2]; // always do vowel_transition, even if ph_VWLEND ?? consider [N] | fmtp.transition0 = phdata_next.vowel_transition[2]; // always do vowel_transition, even if ph_VWLEND ?? consider [N] |
kəmpˈa͡ɪl ænd flˈæʃ lˈɪnɪɪd͡ʒ ˈændɹɔ͡ɪd ˌo͡ʊˈɛs | |||||
kəmpˈa͡ɪl ænd flˈæʃ lˈɪnɪʲɪd͡ʒ ˈændɹɔ͡ɪd ˌo͡ʊˈɛs |
juː hæv fˈɔː͡ɹ nˈuː mˈɛsɪd͡ʒᵻz | juː hæv fˈɔː͡ɹ nˈuː mˈɛsɪd͡ʒᵻz | ||||
ðə fˈɜːst ɪz fɹʌm stˈɛfəni wˈɪljəmz ænd ɚɹˈa͡ɪvd æt | ðə fˈɜːst ɪz fɹʌm stˈɛfəni wˈɪljəmz ænd ɚɹˈa͡ɪvd æt | ||||
θɹˈiː fˈɔː͡ɹɾi fˈa͡ɪv pˌiːˈɛm | |||||
θɹˈiː fˈɔː͡ɹɾi fˈa͡ɪv pˌiːʲˈɛm | |||||
ðə sˈʌbd͡ʒɛkt ɪz skˈiː tɹˈɪp | ðə sˈʌbd͡ʒɛkt ɪz skˈiː tɹˈɪp | ||||