Browse Source

Avoid underflowing ph_list3 (#2082)

master
Samuel Thibault 5 months ago
parent
commit
8afe77ba8e
No account linked to committer's email address

+ 1
- 1
src/libespeak-ng/dictionary.c View File

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) {

+ 6
- 6
src/libespeak-ng/phonemelist.c View File

#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);
} }

+ 3
- 3
src/libespeak-ng/synth_mbrola.c View File



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;

+ 16
- 8
src/libespeak-ng/synthdata.c View File



} }


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);
} }

+ 1
- 0
src/libespeak-ng/synthdata.h View File

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);



+ 11
- 11
src/libespeak-ng/synthesize.c View File

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]

+ 1
- 1
tests/ssml/badly-escaped1.expected View File

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

+ 1
- 1
tests/ssml/spec-example-1.expected View File

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



Loading…
Cancel
Save