espeak-ng / espeak-ng

eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
GNU General Public License v3.0
4.16k stars 895 forks source link

Capital letter indication missing nouns after prepositions in some languages #949

Open pvagner opened 3 years ago

pvagner commented 3 years ago

So far I am able to reproduce this with slovak or czech voices. When calling eSpeak to indicate capital letters with sound the sound is missing after prepositions such as 'na', 'od', 'pred' 'po', 'za' and similar. So when any of these prepositions stands before a person name, the first capital letter of that name is not indicated with sound. When capital letters are indicated with word capital, it is working as expected. See these examples:


espeak -v cs -k 1"bez Libora"
espeak -v cs -k 1"na Libora"```
Change -k 1 to -k 2 to understand indication with word capital is working as it should.
I suspect this might be because of some rules but I can't figure it out on my own so I'd appreciate any hints you can advice.
jaacoppi commented 3 years ago

Looks like a bug that needs changes in the source code. Do you want to try to fix the code by yourself?

The command line parameter -k is handled by int option_capitals. The relevant code is in either readclause.c or translate.c

pvagner commented 3 years ago

Looking at translate.c There is a check of option_capitals on line 1573. However this only does its thing when first letter of a word is capital. The code block which starts at line 1436 in the same file combines prepositions with the main word for some languages e.g. czech, slovak, hungarian and perhaps some others. And doing this affect that later check. It seems there is some other place where capital letter indication in the middle of a word is handled but I can't find it. It's very unlikely I can fix this on my own.

jaacoppi commented 3 years ago

I can look into this as well, but expect to wait a few weeks rather than a few days.

Notes: Looks like the $combine keyword in dictsource/sk_rules is the cause of this problem. There's also FLAG_COMBINE and LOPT_COMBINE_WORDS.

The code block starting around line 1436 of translate.c has calls to TranslateWord() that probaly causes changes in word flags.

jaacoppi commented 3 years ago

My assumption so far:

word_flags is a copy of the flags of the first word: https://github.com/espeak-ng/espeak-ng/blob/40b78f5183f66958b333d8a54f0ab25a9576be5e/src/libespeak-ng/translate.c#L1338

That is checked for FLAG_FIRST_UPPER (First letter is a capital) here: https://github.com/espeak-ng/espeak-ng/blob/40b78f5183f66958b333d8a54f0ab25a9576be5e/src/libespeak-ng/translate.c#L1373

The code block starting here somehow loses FLAG_FIRST_UPPER when combining wtab[0] and wtab[1].

Keeping the FLAG_FIRST_UPPER when combining the words might cause problems elsewhere since bez in "bez Libora" obviously isn't a capital letter.

jaacoppi commented 3 years ago

This is more complicated than I thought.

This line combines the two words and loses FLAG_FIRST_UPPER: https://github.com/espeak-ng/espeak-ng/blob/1df852a1ae8cf0f218c5275b4ed1b69958a46f4e/src/libespeak-ng/translate.c#L1470 Readding the flag would cause a beep before the new combined word.

This block checks for FLAG_FIRST_UPPER and creates the beep / #X1 of -k 1: https://github.com/espeak-ng/espeak-ng/blob/1df852a1ae8cf0f218c5275b4ed1b69958a46f4e/src/libespeak-ng/translate.c#L1573

The problem is that with the example "bez Libora" the beep should be between the two words, not at the beginning of the combined word. I'm pretty sure this added hyphen is tracked somewhere: https://github.com/espeak-ng/espeak-ng/blob/1df852a1ae8cf0f218c5275b4ed1b69958a46f4e/src/libespeak-ng/translate.c#L1468

The place where that hyphen is checked might be a good place to insert the SetPlist2() command. I haven't found it yet.