|
From: Silas S. B. <ss...@ca...> - 2009-01-23 15:32:34
|
Hi Jonathan,
I think we're talking about this code in intonation.cpp:
if(prevw_tph->mnemonic == 0x343132) // [214]
{
if(tph->mnemonic == 0x343132) // [214]
prev_p->tone_ph = PhonemeCode2('3','5');
else
prev_p->tone_ph = PhonemeCode2('2','1');
}
This is wrong anyway. It takes a string of consecutive tone 3's and
turns all but the last one into tone 2s. Sometimes this is acceptable
but not always.
First here is a patch that will change this into the behaviour that I
had previously thought was correct, i.e. making every OTHER 3rd tone
into a 2nd one, going from the end of the sequence backwards (so for
example "ni3 hao3" becomes "ni2 hao3", "wo3 hen3 hao3" becomes "wo3 hen2 hao3")
-------------------- cut here -----------------------------------
--- old-intonation.cpp 2009-01-23 14:50:04.000000000 +0000
+++ intonation.cpp 2009-01-23 15:00:31.000000000 +0000
@@ -759,6 +759,31 @@
}
+ // perform 3rd-tone sandhi for Mandarin (separate loop, going backwards)
+ if(tr->translator_name == L('z','h')) {
+ int next_is_tone3 = 0, end_of_phrase = 1;
+ p = &phoneme_list[n_phoneme_list-1];
+ for(ix=n_phoneme_list-1; ix>=0; ix--, p--) {
+ if((p->type == phPAUSE) && (p->ph->std_length > 50)) {
+ next_is_tone3 = 0; // forget
+ end_of_phrase = 1;
+ } else if(p->synthflags & SFLAG_SYLLABLE) {
+ tone_ph = p->tone_ph;
+ tph = phoneme_tab[tone_ph];
+ if(tph->mnemonic == 0x343132) { // [214]
+ if(next_is_tone3) {
+ p->tone_ph = PhonemeCode2('3','5');
+ next_is_tone3 = 0; // if we changed this one, DON'T change the previous one too
+ } else {
+ next_is_tone3 = 1;
+ if(!end_of_phrase) p->tone_ph = PhonemeCode2('2','1');
+ }
+ }
+ end_of_phrase = 0;
+ }
+ }
+ }
+
pause = 1;
tone_promoted = 0;
@@ -817,18 +842,6 @@
}
}
- if(prevw_tph->mnemonic == 0x343132) // [214]
- {
- if(tph->mnemonic == 0x343132) // [214]
- prev_p->tone_ph = PhonemeCode2('3','5');
- else
- prev_p->tone_ph = PhonemeCode2('2','1');
- }
- if((prev_tph->mnemonic == 0x3135) && (tph->mnemonic == 0x3135)) // [51] + [51]
- {
- prev_p->tone_ph = PhonemeCode2('5','3');
- }
-
if(tph->mnemonic == 0x3131) // [11] Tone 5
{
// tone 5, change its level depending on the previous tone (across word boundaries)
-------------------- cut here -----------------------------------
Some people say the ('3','5') should actually be ('2','4'), i.e. a
slightly lower rising tone, but we'd have to check that natives like the
sound of this. When I tried changing it to ('2','4') I ended up with
[11] which probably means we have to add [24] to some table somewhere
before it will work. I don't know if it's worth trying or not.
Anyway, although applying the above patch should be an improvement, we
still haven't accounted for the new rules. To do this we have to write
something like this before the above loop (sorry it'll have to be half
pseudocode because I'm not entirely sure how to do this in espeak) :
int number_of_syllables_in_this_word = 0;
SyllableType last_syllable = NULL;
for(ix=0; ix<n_phoneme_list; ix++, p++) {
if(p is the start of a new word i.e. it has a space before it or it comes after a pause) {
if(number_of_syllables_in_this_word == 2) {
prev_p -> has_invisible_marker = 1;
}
number_of_syllables_in_this_word = 0;
}
if(p->synthflags & SFLAG_SYLLABLE) {
SyllableType this_syllable = /* the syllable pointed to by p */;
number_of_syllables_in_this_word ++;
/* Implement special rules for "wo3 xiang3" etc */
if (((last_syllable=="wo3" || last_syllable=="ni3") && this_syllable=="xiang3")
|| (last_syllable=="gei3" && (this_syllable=="wo3" || this_syllable=="ni3"))) {
p -> has_invisible_marker = 1;
}
last_syllable = this_syllable; prev_p = p;
}
}
And then the above patch should contain (at the start of the loop),
if (p -> has_invisible_marker) next_is_tone3 = 0; // forget
A test to make sure it's working correctly is:
speak -x -v zh "jiao4dao3 ni3 shi3 ni3 de2yi4chu"
and the expected output is:
_| tS;jAu51t'Au21_| n'i21_| s.'i.35_| n'i21_| t,@35ji51ts.hu11
Let me know when you're ready and I'll send you the zh_listx that puts
in the relevant spaces.
Silas
--
Silas S Brown http://people.pwf.cam.ac.uk/ssb22
|