| unsigned char pitch2; | unsigned char pitch2; | ||||
| } SYLLABLE; | } SYLLABLE; | ||||
| static SYLLABLE *syllable_tab; | |||||
| static int tone_pitch_env; // used to return pitch envelope | static int tone_pitch_env; // used to return pitch envelope | ||||
| /* Pitch data for tone types */ | /* Pitch data for tone types */ | ||||
| static int tone_posn2; | static int tone_posn2; | ||||
| static int no_tonic; | static int no_tonic; | ||||
| static void count_pitch_vowels(int start, int end, int clause_end) | |||||
| static void count_pitch_vowels(SYLLABLE *syllable_tab, int start, int end, int clause_end) | |||||
| { | { | ||||
| int ix; | int ix; | ||||
| int stress; | int stress; | ||||
| } | } | ||||
| // Count number of primary stresses up to tonic syllable or body_reset | // Count number of primary stresses up to tonic syllable or body_reset | ||||
| static int count_increments(int ix, int end_ix, int min_stress) | |||||
| static int count_increments(SYLLABLE *syllable_tab, int ix, int end_ix, int min_stress) | |||||
| { | { | ||||
| int count = 0; | int count = 0; | ||||
| int stress; | int stress; | ||||
| syl->flags |= flags; | syl->flags |= flags; | ||||
| } | } | ||||
| static int CountUnstressed(int start, int end, int limit) | |||||
| static int CountUnstressed(SYLLABLE *syllable_tab, int start, int end, int limit) | |||||
| { | { | ||||
| int ix; | int ix; | ||||
| return ix - start; | return ix - start; | ||||
| } | } | ||||
| static int SetHeadIntonation(TUNE *tune, int syl_ix, int end_ix) | |||||
| static int SetHeadIntonation(SYLLABLE *syllable_tab, TUNE *tune, int syl_ix, int end_ix) | |||||
| { | { | ||||
| int stress; | int stress; | ||||
| SYLLABLE *syl; | SYLLABLE *syl; | ||||
| overflow_ix = 0; | overflow_ix = 0; | ||||
| if (tune->onset == 255) { | if (tune->onset == 255) { | ||||
| n_steps = count_increments(syl_ix, head_final, 4); | |||||
| n_steps = count_increments(syllable_tab, syl_ix, head_final, 4); | |||||
| pitch = tune->head_start << 8; | pitch = tune->head_start << 8; | ||||
| } else { | } else { | ||||
| // a pitch has been specified for the onset syllable, don't include it in the pitch incrementing | // a pitch has been specified for the onset syllable, don't include it in the pitch incrementing | ||||
| n_steps = count_increments(syl_ix+1, head_final, 4); | |||||
| n_steps = count_increments(syllable_tab, syl_ix+1, head_final, 4); | |||||
| pitch = tune->onset << 8; | pitch = tune->onset << 8; | ||||
| used_onset = 1; | used_onset = 1; | ||||
| } | } | ||||
| } | } | ||||
| if (stress >= PRIMARY) { | if (stress >= PRIMARY) { | ||||
| n_unstressed = CountUnstressed(syl_ix+1, end_ix, secondary); | |||||
| n_unstressed = CountUnstressed(syllable_tab, syl_ix+1, end_ix, secondary); | |||||
| unstressed_ix = 0; | unstressed_ix = 0; | ||||
| syl->stress = PRIMARY_STRESSED; | syl->stress = PRIMARY_STRESSED; | ||||
| syl->env = tune->stressed_env; | syl->env = tune->stressed_env; | ||||
| set_pitch(syl, (pitch >> 8), tune->stressed_drop); | set_pitch(syl, (pitch >> 8), tune->stressed_drop); | ||||
| } else if (stress >= secondary) { | } else if (stress >= secondary) { | ||||
| n_unstressed = CountUnstressed(syl_ix+1, end_ix, secondary); | |||||
| n_unstressed = CountUnstressed(syllable_tab, syl_ix+1, end_ix, secondary); | |||||
| unstressed_ix = 0; | unstressed_ix = 0; | ||||
| set_pitch(syl, (pitch >> 8), drops[stress]); | set_pitch(syl, (pitch >> 8), drops[stress]); | ||||
| } else { | } else { | ||||
| /* Calculate pitches until next RESET or tonic syllable, or end. | /* Calculate pitches until next RESET or tonic syllable, or end. | ||||
| Increment pitch if stress is >= min_stress. | Increment pitch if stress is >= min_stress. | ||||
| Used for tonic segment */ | Used for tonic segment */ | ||||
| static int calc_pitch_segment(int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, int continuing) | |||||
| static int calc_pitch_segment(SYLLABLE *syllable_tab, int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, int continuing) | |||||
| { | { | ||||
| int stress; | int stress; | ||||
| int pitch = 0; | int pitch = 0; | ||||
| if ((initial) || (stress == 5)) { | if ((initial) || (stress == 5)) { | ||||
| initial = 0; | initial = 0; | ||||
| overflow = 0; | overflow = 0; | ||||
| n_steps = n_primary = count_increments(ix, end_ix, min_stress); | |||||
| n_steps = n_primary = count_increments(syllable_tab, ix, end_ix, min_stress); | |||||
| if (n_steps > th->body_max_steps) | if (n_steps > th->body_max_steps) | ||||
| n_steps = th->body_max_steps; | n_steps = th->body_max_steps; | ||||
| return ix; | return ix; | ||||
| } | } | ||||
| static void SetPitchGradient(int start_ix, int end_ix, int start_pitch, int end_pitch) | |||||
| static void SetPitchGradient(SYLLABLE *syllable_tab, int start_ix, int end_ix, int start_pitch, int end_pitch) | |||||
| { | { | ||||
| // Set a linear pitch change over a number of syllables. | // Set a linear pitch change over a number of syllables. | ||||
| // Used for pre-head, unstressed syllables in the body, and the tail | // Used for pre-head, unstressed syllables in the body, and the tail | ||||
| } | } | ||||
| // Calculate pitch values for the vowels in this tone group | // Calculate pitch values for the vowels in this tone group | ||||
| static int calc_pitches2(int start, int end, int tune_number) | |||||
| static int calc_pitches2(SYLLABLE *syllable_tab, int start, int end, int tune_number) | |||||
| { | { | ||||
| int ix; | int ix; | ||||
| TUNE *tune; | TUNE *tune; | ||||
| // vowels before the first primary stress | // vowels before the first primary stress | ||||
| SetPitchGradient(ix, ix+number_pre, tune->prehead_start, tune->prehead_end); | |||||
| SetPitchGradient(syllable_tab, ix, ix+number_pre, tune->prehead_start, tune->prehead_end); | |||||
| ix += number_pre; | ix += number_pre; | ||||
| // body of tonic segment | // body of tonic segment | ||||
| if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE) | if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE) | ||||
| tone_posn = tone_posn2; // put tone on the penultimate stressed word | tone_posn = tone_posn2; // put tone on the penultimate stressed word | ||||
| ix = SetHeadIntonation(tune, ix, tone_posn); | |||||
| ix = SetHeadIntonation(syllable_tab, tune, ix, tone_posn); | |||||
| if (no_tonic) | if (no_tonic) | ||||
| return 0; | return 0; | ||||
| // tail, after the tonic syllable | // tail, after the tonic syllable | ||||
| SetPitchGradient(ix, end, tune->tail_start, tune->tail_end); | |||||
| SetPitchGradient(syllable_tab, ix, end, tune->tail_start, tune->tail_end); | |||||
| return tone_pitch_env; | return tone_pitch_env; | ||||
| } | } | ||||
| // Calculate pitch values for the vowels in this tone group | // Calculate pitch values for the vowels in this tone group | ||||
| static int calc_pitches(int control, int start, int end, int tune_number) | |||||
| static int calc_pitches(SYLLABLE *syllable_tab, int control, int start, int end, int tune_number) | |||||
| { | { | ||||
| int ix; | int ix; | ||||
| TONE_HEAD *th; | TONE_HEAD *th; | ||||
| int continuing = 0; | int continuing = 0; | ||||
| if (control == 0) | if (control == 0) | ||||
| return calc_pitches2(start, end, tune_number); | |||||
| return calc_pitches2(syllable_tab, start, end, tune_number); | |||||
| if (start > 0) | if (start > 0) | ||||
| continuing = 1; | continuing = 1; | ||||
| // vowels before the first primary stress | // vowels before the first primary stress | ||||
| SetPitchGradient(ix, ix+number_pre, th->pre_start, th->pre_end); | |||||
| SetPitchGradient(syllable_tab, ix, ix+number_pre, th->pre_start, th->pre_end); | |||||
| ix += number_pre; | ix += number_pre; | ||||
| // body of tonic segment | // body of tonic segment | ||||
| if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE) | if (option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE) | ||||
| tone_posn = tone_posn2; // put tone on the penultimate stressed word | tone_posn = tone_posn2; // put tone on the penultimate stressed word | ||||
| ix = calc_pitch_segment(ix, tone_posn, th, tn, PRIMARY, continuing); | |||||
| ix = calc_pitch_segment(syllable_tab, ix, tone_posn, th, tn, PRIMARY, continuing); | |||||
| if (no_tonic) | if (no_tonic) | ||||
| return 0; | return 0; | ||||
| // tail, after the tonic syllable | // tail, after the tonic syllable | ||||
| SetPitchGradient(ix, end, tn->tail_start, tn->tail_end); | |||||
| SetPitchGradient(syllable_tab, ix, end, tn->tail_start, tn->tail_end); | |||||
| return tone_pitch_env; | return tone_pitch_env; | ||||
| } | } | ||||
| PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
| int ph_end = n_phoneme_list; | int ph_end = n_phoneme_list; | ||||
| SYLLABLE syllable_tab2[N_PHONEME_LIST]; | |||||
| syllable_tab = syllable_tab2; // don't use permanent storage. it's only needed during the call of CalcPitches() | |||||
| SYLLABLE syllable_tab[N_PHONEME_LIST]; | |||||
| n_st = 0; | n_st = 0; | ||||
| n_primary = 0; | n_primary = 0; | ||||
| for (ix = 0; ix < (n_phoneme_list-1); ix++) { | for (ix = 0; ix < (n_phoneme_list-1); ix++) { | ||||
| } | } | ||||
| } | } | ||||
| count_pitch_vowels(st_start, ix, n_st); | |||||
| count_pitch_vowels(syllable_tab, st_start, ix, n_st); | |||||
| if ((ix < n_st) || (clause_type == 0)) { | if ((ix < n_st) || (clause_type == 0)) { | ||||
| calc_pitches(option, st_start, ix, group_tone); // split into > 1 tone groups | |||||
| calc_pitches(syllable_tab, option, st_start, ix, group_tone); // split into > 1 tone groups | |||||
| if ((clause_type == 1) || (clause_type == 2)) | if ((clause_type == 1) || (clause_type == 2)) | ||||
| group_tone = tr->langopts.tunes[1]; // , or ? remainder has comma-tone | group_tone = tr->langopts.tunes[1]; // , or ? remainder has comma-tone | ||||
| else | else | ||||
| group_tone = tr->langopts.tunes[0]; // . or ! remainder has statement tone | group_tone = tr->langopts.tunes[0]; // . or ! remainder has statement tone | ||||
| } else | } else | ||||
| calc_pitches(option, st_start, ix, group_tone); | |||||
| calc_pitches(syllable_tab, option, st_start, ix, group_tone); | |||||
| st_start = ix; | st_start = ix; | ||||
| } | } | ||||
| if ((st_start < st_ix) && (syl->flags & SYL_END_CLAUSE)) { | if ((st_start < st_ix) && (syl->flags & SYL_END_CLAUSE)) { | ||||
| // end of clause after this syllable, indicated by a phonPAUSE_CLAUSE phoneme | // end of clause after this syllable, indicated by a phonPAUSE_CLAUSE phoneme | ||||
| st_clause_end = st_ix+1; | st_clause_end = st_ix+1; | ||||
| count_pitch_vowels(st_start, st_clause_end, st_clause_end); | |||||
| calc_pitches(option, st_start, st_clause_end, group_tone_comma); | |||||
| count_pitch_vowels(syllable_tab, st_start, st_clause_end, st_clause_end); | |||||
| calc_pitches(syllable_tab, option, st_start, st_clause_end, group_tone_comma); | |||||
| st_start = st_clause_end; | st_start = st_clause_end; | ||||
| } | } | ||||
| } | } | ||||
| if (st_start < st_ix) { | if (st_start < st_ix) { | ||||
| count_pitch_vowels(st_start, st_ix, n_st); | |||||
| calc_pitches(option, st_start, st_ix, group_tone); | |||||
| count_pitch_vowels(syllable_tab, st_start, st_ix, n_st); | |||||
| calc_pitches(syllable_tab, option, st_start, st_ix, group_tone); | |||||
| } | } | ||||
| // unpack pitch data | // unpack pitch data |