PageRenderTime 103ms CodeModel.GetById 13ms app.highlight 80ms RepoModel.GetById 1ms app.codeStats 1ms

/native/external/espeak/src/intonation.cpp

http://eyes-free.googlecode.com/
C++ | 1104 lines | 813 code | 209 blank | 82 comment | 149 complexity | ed3088cbd6a91485f6b89233ffe30375 MD5 | raw file
   1/***************************************************************************
   2 *   Copyright (C) 2005 to 2007 by Jonathan Duddington                     *
   3 *   email: jonsd@users.sourceforge.net                                    *
   4 *                                                                         *
   5 *   This program is free software; you can redistribute it and/or modify  *
   6 *   it under the terms of the GNU General Public License as published by  *
   7 *   the Free Software Foundation; either version 3 of the License, or     *
   8 *   (at your option) any later version.                                   *
   9 *                                                                         *
  10 *   This program is distributed in the hope that it will be useful,       *
  11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
  12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
  13 *   GNU General Public License for more details.                          *
  14 *                                                                         *
  15 *   You should have received a copy of the GNU General Public License     *
  16 *   along with this program; if not, write see:                           *
  17 *               <http://www.gnu.org/licenses/>.                           *
  18 ***************************************************************************/
  19
  20#include "StdAfx.h"
  21
  22#include <stdio.h>
  23#include <string.h>
  24#include <wctype.h>
  25
  26#include "speak_lib.h"
  27#include "speech.h"
  28#include "phoneme.h"
  29#include "synthesize.h"
  30#include "voice.h"
  31#include "translate.h"
  32
  33
  34/* Note this module is mostly old code that needs to be rewritten to
  35   provide a more flexible intonation system.
  36*/
  37
  38// bits in SYLLABLE.flags
  39#define SYL_RISE        1
  40#define SYL_EMPHASIS    2
  41#define SYL_END_CLAUSE   4
  42
  43typedef struct {
  44	char stress;
  45	char env;
  46	char flags;   //bit 0=pitch rising, bit1=emnphasized, bit2=end of clause
  47	char nextph_type;
  48	short pitch1;
  49	short pitch2;
  50} SYLLABLE;
  51
  52SYLLABLE *syllable_tab;
  53
  54
  55static int tone_pitch_env;    /* used to return pitch envelope */
  56
  57
  58
  59/* Pitch data for tone types */
  60/*****************************/
  61
  62
  63#define    PITCHfall   0
  64#define    PITCHrise   1
  65#define    PITCHfrise  2   // and 3 must be for the varient preceded by 'r'
  66#define    PITCHfrise2 4   // and 5 must be the 'r' variant
  67#define    PITCHrisefall   6
  68
  69/*  0  fall */
  70unsigned char env_fall[128] = {
  71 0xff, 0xfd, 0xfa, 0xf8, 0xf6, 0xf4, 0xf2, 0xf0, 0xee, 0xec, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0,
  72 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xd0, 0xce, 0xcc, 0xca, 0xc8, 0xc6, 0xc4, 0xc2, 0xc0,
  73 0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0, 0xae, 0xac, 0xaa, 0xa8, 0xa6, 0xa4, 0xa2, 0xa0,
  74 0x9e, 0x9c, 0x9a, 0x98, 0x96, 0x94, 0x92, 0x90, 0x8e, 0x8c, 0x8a, 0x88, 0x86, 0x84, 0x82, 0x80,
  75 0x7e, 0x7c, 0x7a, 0x78, 0x76, 0x74, 0x72, 0x70, 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x62, 0x60,
  76 0x5e, 0x5c, 0x5a, 0x58, 0x56, 0x54, 0x52, 0x50, 0x4e, 0x4c, 0x4a, 0x48, 0x46, 0x44, 0x42, 0x40,
  77 0x3e, 0x3c, 0x3a, 0x38, 0x36, 0x34, 0x32, 0x30, 0x2e, 0x2c, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20,
  78 0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x00 };
  79
  80/*  1  rise */
  81unsigned char env_rise[128] = {
  82 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
  83 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
  84 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
  85 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
  86 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
  87 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
  88 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
  89 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfd, 0xff };
  90
  91unsigned char env_frise[128] = {
  92 0xff, 0xf4, 0xea, 0xe0, 0xd6, 0xcc, 0xc3, 0xba, 0xb1, 0xa8, 0x9f, 0x97, 0x8f, 0x87, 0x7f, 0x78,
  93 0x71, 0x6a, 0x63, 0x5c, 0x56, 0x50, 0x4a, 0x44, 0x3f, 0x39, 0x34, 0x2f, 0x2b, 0x26, 0x22, 0x1e,
  94 0x1a, 0x17, 0x13, 0x10, 0x0d, 0x0b, 0x08, 0x06, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  95 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x13, 0x15, 0x17,
  96 0x1a, 0x1d, 0x1f, 0x22, 0x25, 0x28, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x39, 0x3b, 0x3d, 0x40,
  97 0x42, 0x45, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x54, 0x57, 0x5a, 0x5d, 0x5f, 0x62, 0x65, 0x68, 0x6b,
  98 0x6e, 0x71, 0x74, 0x78, 0x7b, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa0,
  99 0xa4, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xbb, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xe0 };
 100
 101static unsigned char env_r_frise[128] = {
 102 0xcf, 0xcc, 0xc9, 0xc6, 0xc3, 0xc0, 0xbd, 0xb9, 0xb4, 0xb0, 0xab, 0xa7, 0xa2, 0x9c, 0x97, 0x92,
 103 0x8c, 0x86, 0x81, 0x7b, 0x75, 0x6f, 0x69, 0x63, 0x5d, 0x57, 0x50, 0x4a, 0x44, 0x3e, 0x38, 0x33,
 104 0x2d, 0x27, 0x22, 0x1c, 0x17, 0x12, 0x0d, 0x08, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
 105 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x12, 0x14, 0x16,
 106 0x19, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, 0x30, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3f, 0x41,
 107 0x43, 0x46, 0x48, 0x4b, 0x4d, 0x50, 0x52, 0x55, 0x58, 0x5a, 0x5d, 0x60, 0x63, 0x66, 0x69, 0x6c,
 108 0x6f, 0x72, 0x75, 0x78, 0x7b, 0x7e, 0x81, 0x85, 0x88, 0x8b, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa0,
 109 0xa4, 0xa8, 0xac, 0xaf, 0xb3, 0xb7, 0xbb, 0xbf, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7, 0xdb, 0xe0 };
 110
 111static unsigned char env_frise2[128] = {
 112 0xff, 0xf9, 0xf4, 0xee, 0xe9, 0xe4, 0xdf, 0xda, 0xd5, 0xd0, 0xcb, 0xc6, 0xc1, 0xbd, 0xb8, 0xb3,
 113 0xaf, 0xaa, 0xa6, 0xa1, 0x9d, 0x99, 0x95, 0x90, 0x8c, 0x88, 0x84, 0x80, 0x7d, 0x79, 0x75, 0x71,
 114 0x6e, 0x6a, 0x67, 0x63, 0x60, 0x5d, 0x59, 0x56, 0x53, 0x50, 0x4d, 0x4a, 0x47, 0x44, 0x41, 0x3e,
 115 0x3c, 0x39, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2b, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a,
 116 0x19, 0x17, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05,
 117 0x05, 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 118 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08,
 119 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20 };
 120
 121static unsigned char env_r_frise2[128] = {
 122 0xd0, 0xce, 0xcd, 0xcc, 0xca, 0xc8, 0xc7, 0xc5, 0xc3, 0xc1, 0xc0, 0xbd, 0xbb, 0xb8, 0xb5, 0xb3,
 123 0xb0, 0xad, 0xaa, 0xa7, 0xa3, 0xa0, 0x9d, 0x99, 0x96, 0x92, 0x8f, 0x8b, 0x87, 0x84, 0x80, 0x7c,
 124 0x78, 0x74, 0x70, 0x6d, 0x69, 0x65, 0x61, 0x5d, 0x59, 0x55, 0x51, 0x4d, 0x4a, 0x46, 0x42, 0x3e,
 125 0x3b, 0x37, 0x34, 0x31, 0x2f, 0x2d, 0x2a, 0x28, 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x19,
 126 0x17, 0x15, 0x14, 0x12, 0x11, 0x0f, 0x0e, 0x0d, 0x0c, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x05,
 127 0x04, 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 128 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x04, 0x04, 0x05, 0x06, 0x07, 0x08,
 129 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x0f, 0x10, 0x12, 0x13, 0x15, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20 };
 130
 131static unsigned char env_risefall[128] = {
 132 0x98, 0x99, 0x99, 0x9a, 0x9c, 0x9d, 0x9f, 0xa1, 0xa4, 0xa7, 0xa9, 0xac, 0xb0, 0xb3, 0xb6, 0xba,
 133 0xbe, 0xc1, 0xc5, 0xc9, 0xcd, 0xd1, 0xd4, 0xd8, 0xdc, 0xdf, 0xe3, 0xe6, 0xea, 0xed, 0xf0, 0xf2,
 134 0xf5, 0xf7, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd,
 135 0xfb, 0xfa, 0xf8, 0xf6, 0xf3, 0xf1, 0xee, 0xec, 0xe9, 0xe6, 0xe4, 0xe0, 0xdd, 0xda, 0xd7, 0xd3,
 136 0xd0, 0xcc, 0xc8, 0xc4, 0xc0, 0xbc, 0xb8, 0xb4, 0xb0, 0xac, 0xa7, 0xa3, 0x9f, 0x9a, 0x96, 0x91,
 137 0x8d, 0x88, 0x84, 0x7f, 0x7b, 0x76, 0x72, 0x6d, 0x69, 0x65, 0x60, 0x5c, 0x58, 0x54, 0x50, 0x4c,
 138 0x48, 0x44, 0x40, 0x3c, 0x39, 0x35, 0x32, 0x2f, 0x2b, 0x28, 0x26, 0x23, 0x20, 0x1d, 0x1a, 0x17,
 139 0x15, 0x12, 0x0f, 0x0d, 0x0a, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
 140
 141static unsigned char env_rise2[128] = {
 142 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x06, 0x06,
 143 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
 144 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1d, 0x1f, 0x20, 0x22, 0x23, 0x25, 0x26, 0x28, 0x29, 0x2b,
 145 0x2d, 0x2f, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x47, 0x49, 0x4b,
 146 0x4e, 0x50, 0x52, 0x55, 0x57, 0x5a, 0x5d, 0x5f, 0x62, 0x65, 0x67, 0x6a, 0x6d, 0x70, 0x73, 0x76,
 147 0x79, 0x7c, 0x7f, 0x82, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x96, 0x9a, 0x9d, 0xa0, 0xa3, 0xa6, 0xa9,
 148 0xac, 0xaf, 0xb2, 0xb5, 0xb8, 0xbb, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd, 0xd0, 0xd3, 0xd6, 0xd9,
 149 0xdc, 0xdf, 0xe2, 0xe4, 0xe7, 0xe9, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfb, 0xfd };
 150
 151static unsigned char env_fall2[128] = {
 152 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf6, 0xf6,
 153 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, 0xf0, 0xf0, 0xef, 0xee, 0xee, 0xed, 0xec, 0xeb,
 154 0xea, 0xea, 0xe9, 0xe8, 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xde, 0xdd, 0xdc, 0xdb,
 155 0xd9, 0xd8, 0xd6, 0xd5, 0xd3, 0xd2, 0xd0, 0xce, 0xcc, 0xcb, 0xc9, 0xc7, 0xc5, 0xc3, 0xc0, 0xbe,
 156 0xbc, 0xb9, 0xb7, 0xb5, 0xb2, 0xaf, 0xad, 0xaa, 0xa7, 0xa4, 0xa1, 0x9e, 0x9a, 0x97, 0x94, 0x90,
 157 0x8d, 0x89, 0x85, 0x81, 0x7d, 0x79, 0x75, 0x71, 0x6d, 0x68, 0x64, 0x61, 0x5e, 0x5b, 0x57, 0x54,
 158 0x51, 0x4d, 0x4a, 0x46, 0x43, 0x40, 0x3c, 0x39, 0x35, 0x32, 0x2e, 0x2a, 0x27, 0x23, 0x1f, 0x1c,
 159 0x18, 0x14, 0x11, 0x0d, 0x0b, 0x09, 0x07, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00 };
 160
 161static unsigned char env_fallrise3[128] = {
 162 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, 0xf6, 0xf4, 0xf1, 0xee, 0xeb,
 163 0xe8, 0xe5, 0xe1, 0xde, 0xda, 0xd6, 0xd2, 0xcd, 0xc9, 0xc4, 0xbf, 0xba, 0xb6, 0xb0, 0xab, 0xa6,
 164 0xa1, 0x9c, 0x96, 0x91, 0x8b, 0x86, 0x80, 0x7b, 0x75, 0x6f, 0x6a, 0x64, 0x5f, 0x59, 0x54, 0x4f,
 165 0x49, 0x44, 0x3f, 0x3a, 0x35, 0x30, 0x2b, 0x26, 0x22, 0x1d, 0x19, 0x15, 0x11, 0x0d, 0x0a, 0x07,
 166 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x04, 0x05,
 167 0x07, 0x09, 0x0b, 0x0d, 0x10, 0x12, 0x15, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
 168 0x3a, 0x3e, 0x43, 0x48, 0x4c, 0x51, 0x57, 0x5b, 0x5e, 0x62, 0x65, 0x68, 0x6b, 0x6e, 0x71, 0x74,
 169 0x76, 0x78, 0x7b, 0x7c, 0x7e, 0x80, 0x81, 0x82, 0x83, 0x83, 0x84, 0x84, 0x83, 0x83, 0x82, 0x81 };
 170
 171static unsigned char env_fallrise4[128] = {
 172 0x72, 0x72, 0x71, 0x71, 0x70, 0x6f, 0x6d, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x61, 0x5f, 0x5c, 0x5a,
 173 0x57, 0x54, 0x51, 0x4e, 0x4b, 0x48, 0x45, 0x42, 0x3f, 0x3b, 0x38, 0x35, 0x32, 0x2f, 0x2c, 0x29,
 174 0x26, 0x23, 0x20, 0x1d, 0x1b, 0x18, 0x16, 0x14, 0x12, 0x10, 0x0e, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
 175 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
 176 0x07, 0x07, 0x08, 0x09, 0x0a, 0x0c, 0x0d, 0x0f, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1d, 0x20,
 177 0x23, 0x26, 0x29, 0x2c, 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, 0x47, 0x4c, 0x51, 0x56, 0x5b, 0x60,
 178 0x65, 0x6a, 0x6f, 0x74, 0x79, 0x7f, 0x84, 0x89, 0x8f, 0x95, 0x9b, 0xa1, 0xa7, 0xad, 0xb3, 0xba,
 179 0xc0, 0xc7, 0xce, 0xd5, 0xdc, 0xe3, 0xea, 0xf1, 0xf5, 0xf7, 0xfa, 0xfc, 0xfd, 0xfe, 0xff, 0xff };
 180
 181static unsigned char env_risefallrise[128] = {
 182 0x7f, 0x7f, 0x7f, 0x80, 0x81, 0x83, 0x84, 0x87, 0x89, 0x8c, 0x8f, 0x92, 0x96, 0x99, 0x9d, 0xa1,
 183 0xa5, 0xaa, 0xae, 0xb2, 0xb7, 0xbb, 0xc0, 0xc5, 0xc9, 0xcd, 0xd2, 0xd6, 0xda, 0xde, 0xe2, 0xe6,
 184 0xea, 0xed, 0xf0, 0xf3, 0xf5, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xfd, 0xfc, 0xfb, 0xf9,
 185 0xf7, 0xf4, 0xf0, 0xec, 0xe7, 0xe2, 0xdc, 0xd5, 0xce, 0xc6, 0xbd, 0xb4, 0xa9, 0x9e, 0x92, 0x88,
 186 0x82, 0x7d, 0x77, 0x72, 0x6c, 0x66, 0x60, 0x5a, 0x54, 0x4e, 0x49, 0x42, 0x3c, 0x37, 0x32, 0x2d,
 187 0x28, 0x24, 0x1f, 0x1b, 0x18, 0x14, 0x11, 0x0e, 0x0c, 0x09, 0x07, 0x06, 0x05, 0x04, 0x04, 0x04,
 188 0x04, 0x05, 0x06, 0x08, 0x0a, 0x0d, 0x10, 0x14, 0x18, 0x1d, 0x23, 0x29, 0x2f, 0x37, 0x3e, 0x47,
 189 0x50, 0x5a, 0x64, 0x70, 0x7c, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8e, 0x8f, 0x91, 0x92, 0x93, 0x93 };
 190
 191
 192
 193
 194unsigned char *envelope_data[18] = {
 195	env_fall,
 196	env_rise,
 197	env_frise,  env_r_frise,
 198	env_frise2, env_r_frise2,
 199	env_risefall, env_risefall,
 200
 201	env_fallrise3, env_fallrise3,
 202	env_fallrise4, env_fallrise4,
 203	env_fall2, env_fall2,
 204	env_rise2, env_rise2,
 205	env_risefallrise, env_risefallrise
 206 };
 207
 208
 209/* all pitches given in Hz above pitch_base */
 210
 211// pitch change during the main part of the clause
 212static int drops_0[8] = {0x400,0x400,0x700,0x700,0x700,0xa00,0x1800,0x0e00};
 213//static int drops_1[8] = {0x400,0x400,0x600,0x600,0xc00,0xc00,0x0e00,0x0e00};
 214//static int drops_2[8] = {0x400,0x400,0x600,0x600,-0x800,0xc00,0x0e00,0x0e00};
 215
 216static short oflow[] = {0, 20, 12, 4, 0};
 217static short oflow_emf[] = {5, 24, 15, 10, 5};
 218static short oflow_less[] = {3, 19, 12, 7, 2};
 219// static short oflow_test2[] = {20, 0, 20, 0, 20};
 220// static short back_emf[] = {35, 32, 0};
 221
 222
 223#define N_TONE_HEAD_TABLE  13
 224#define N_TONE_NUCLEUS_TABLE  13
 225
 226
 227typedef struct {
 228	unsigned char pre_start;
 229	unsigned char pre_end;
 230
 231	unsigned char body_start;
 232	unsigned char body_end;
 233
 234	int  *body_drops;
 235	unsigned char body_max_steps;
 236	char body_lower_u;
 237
 238	char n_overflow;
 239	short *overflow;
 240} TONE_HEAD;
 241
 242
 243typedef struct {
 244	unsigned char pitch_env0;     /* pitch envelope, tonic syllable at end */
 245	unsigned char tonic_max0;
 246	unsigned char tonic_min0;
 247
 248	unsigned char pitch_env1;     /*     followed by unstressed */
 249	unsigned char tonic_max1;
 250	unsigned char tonic_min1;
 251
 252	short *backwards;
 253
 254	unsigned char tail_start;
 255	unsigned char tail_end;
 256	unsigned char flags;
 257} TONE_NUCLEUS;
 258
 259#define T_EMPH  1
 260
 261static TONE_HEAD tone_head_table[N_TONE_HEAD_TABLE] = {
 262   {20, 25,   34, 22,  drops_0, 3, 3,   5, oflow},      // 0 statement
 263   {20, 25,   34, 20,  drops_0, 3, 3,   5, oflow},      // 1 comma
 264   {20, 25,   34, 20,  drops_0, 3, 3,   5, oflow},      // 2 question
 265   {20, 25,   36, 22,  drops_0, 3, 4,   5, oflow_emf},  // 3 exclamation
 266   {20, 25,   34, 22,  drops_0, 3, 3,   5, oflow},      // 4 statement, emphatic
 267   {20, 25,   32, 24,  drops_0, 4, 3,   5, oflow_less}, // 5 statement, less intonation
 268   {20, 25,   32, 24,  drops_0, 4, 3,   5, oflow_less}, // 6 comma, less intonation
 269   {20, 25,   32, 24,  drops_0, 4, 3,   5, oflow_less}, // 7 comma, less intonation, less rise
 270   {20, 25,   34, 22,  drops_0, 3, 3,   5, oflow},      // 8 pitch raises at end of sentence
 271   {20, 25,   34, 20,  drops_0, 3, 3,   5, oflow},      // 9 comma
 272   {20, 25,   34, 22,  drops_0, 3, 3,   5, oflow},      // 10  question
 273   {15, 18,   18, 14,  drops_0, 3, 3,   5, oflow_less},   // 11 test
 274   {20, 25,   24, 22,  drops_0, 3, 3,   5, oflow_less},   // 12 test
 275};
 276
 277static TONE_NUCLEUS tone_nucleus_table[N_TONE_NUCLEUS_TABLE] = {
 278   {PITCHfall,   30, 5,  PITCHfall,   32, 9, NULL, 12, 7, 0},      // 0 statement
 279   {PITCHfrise,  35, 8,  PITCHfrise2, 35,10, NULL, 15, 23, 0},     // 1 comma
 280   {PITCHfrise,  39,10,  PITCHfrise2, 36,10, NULL, 15, 28, 0},     // 2 question
 281//   {PITCHfall,   41, 4,  PITCHfall,   41,27, NULL, 16, 4, T_EMPH},  // 3 exclamation
 282   {PITCHfall,   41, 4,  PITCHfall,   41,35, NULL, 35, 4, T_EMPH},  // 3 exclamation
 283   {PITCHfall,   38, 2,  PITCHfall,   42,30, NULL, 15, 5, 0},      // 4 statement, emphatic
 284   {PITCHfall,   28, 5,  PITCHfall,   28, 9, NULL, 12, 7, 0},      // 5 statement, less intonation
 285   {PITCHfrise,  30, 8,  PITCHfrise2, 30,10, NULL, 13, 20, 0},      // 6 comma, less intonation
 286   {PITCHfrise2, 28, 7,  PITCHfall,   29,14, NULL, 14, 8, 0},      // 7 comma, less intonation, less rise
 287   {PITCHrise,   30,20,  PITCHfall,   19,14, NULL, 20, 26, 0},     // 8 pitch raises at end of sentence
 288   {PITCHfrise,  35,11,  PITCHfrise2, 32,10, NULL, 19, 24, 0},     // 9 comma
 289   {PITCHfrise,  39,15,  PITCHfall,   28,14, NULL, 20, 36, 0},     // 10  question
 290   {PITCHfall,   28, 6,  PITCHfall,   28,10, NULL, 12, 6, 0},      // 11 test
 291   {PITCHfall,   35, 9,  PITCHfall,   35,12, NULL, 16, 10, 0},     // 12 test
 292};
 293  
 294
 295
 296/* index by 0=. 1=, 2=?, 3=! 4=none, 5=emphasized */
 297unsigned char punctuation_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS] = {
 298	{0,1,2,3,0,4},
 299	{0,1,2,3,0,4},
 300	{5,6,2,3,0,4},
 301	{5,7,1,3,0,4},
 302	{8,9,10,3,0,0},
 303	{8,8,10,3,0,0},
 304	{11,11,11,11,0,0},  // 6 test
 305	{12,12,12,12,0,0}
 306};
 307
 308
 309
 310/* indexed by stress */
 311static int min_drop[] =  {0x300,0x300,0x400,0x400,0x900,0x900,0x900,0xb00};
 312
 313
 314
 315
 316#define SECONDARY  3
 317#define PRIMARY    4
 318#define PRIMARY_STRESSED 6
 319#define PRIMARY_LAST 7
 320
 321
 322static int  number_pre;
 323static int  number_body;
 324static int  number_tail;
 325static int  last_primary;
 326static int  tone_posn;
 327static int  tone_posn2;
 328static int  no_tonic;
 329
 330
 331static void count_pitch_vowels(int start, int end, int clause_end)
 332/****************************************************************/
 333{
 334	int  ix;
 335	int  stress;
 336	int  max_stress = 0;
 337	int  max_stress_posn = 0;  // last syllable ot the highest stress
 338	int  max_stress_posn2 = 0;  // penuntimate syllable of the highest stress
 339
 340	number_pre = -1;    /* number of vowels before 1st primary stress */
 341	number_body = 0;
 342	number_tail = 0;   /* number between tonic syllable and next primary */
 343	last_primary = -1;
 344	
 345	for(ix=start; ix<end; ix++)
 346	{
 347		stress = syllable_tab[ix].stress;   /* marked stress level */
 348
 349		if(stress >= max_stress)
 350		{
 351			if(stress > max_stress)
 352			{
 353				max_stress_posn2 = ix;
 354			}
 355			else
 356			{
 357				max_stress_posn2 = max_stress_posn;
 358			}
 359			max_stress_posn = ix;
 360			max_stress = stress;
 361		}
 362		if(stress >= PRIMARY)
 363		{
 364			if(number_pre < 0)
 365				number_pre = ix - start;
 366
 367			last_primary = ix;
 368		}
 369
 370	}
 371
 372	if(number_pre < 0)
 373		number_pre = end;
 374
 375	number_tail = end - max_stress_posn - 1;
 376	tone_posn = max_stress_posn;
 377	tone_posn2 = max_stress_posn2;
 378
 379	if(no_tonic)
 380	{
 381		tone_posn = tone_posn2 = end;  // next position after the end of the truncated clause
 382	}
 383	else
 384	if(last_primary >= 0)
 385	{
 386		if(end == clause_end)
 387		{
 388			syllable_tab[last_primary].stress = PRIMARY_LAST;
 389		}
 390	}
 391	else
 392	{
 393		// no primary stress. Use the highest stress
 394		syllable_tab[tone_posn].stress = PRIMARY_LAST;
 395	}
 396}   /* end of count_pitch_vowels */
 397
 398
 399
 400
 401static int count_increments(int ix, int end_ix, int min_stress)
 402/*************************************************************/
 403/* Count number of primary stresses up to tonic syllable or body_reset */
 404{
 405	int  count = 0;
 406	int  stress;
 407
 408	while(ix < end_ix)
 409	{
 410		stress = syllable_tab[ix++].stress;
 411		if(stress >= PRIMARY_LAST)
 412			break;
 413
 414		if(stress >= min_stress)
 415			count++;
 416	}
 417	return(count);
 418}  /* end of count_increments */
 419
 420
 421
 422static void set_pitch(SYLLABLE *syl, int base, int drop)
 423/******************************************************/
 424// Set the pitch of a vowel in syllable_tab.  Base & drop are Hz * 256
 425{
 426	int  pitch1, pitch2;
 427	int  flags = 0;
 428
 429	/* adjust experimentally */
 430	int  pitch_range2 = 148;
 431	int  pitch_base2 = 72;
 432
 433	if(base < 0)  base = 0;
 434
 435	pitch2 = ((base * pitch_range2 ) >> 15) + pitch_base2;
 436
 437	if(drop < 0)
 438	{
 439		flags = SYL_RISE;
 440		drop = -drop;
 441	}
 442
 443	pitch1 = pitch2 + ((drop * pitch_range2) >> 15);
 444
 445	if(pitch1 > 511) pitch1 = 511;
 446	if(pitch2 > 511) pitch2 = 511;
 447
 448	syl->pitch1 = pitch1;
 449	syl->pitch2 = pitch2;
 450	syl->flags |= flags;
 451}   /* end of set_pitch */
 452
 453
 454
 455static int calc_pitch_segment(int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, int continuing)
 456/**********************************************************************************************/
 457/* Calculate pitches until next RESET or tonic syllable, or end.
 458	Increment pitch if stress is >= min_stress.
 459	Used for tonic segment */
 460{
 461	int  stress;
 462	int  pitch=0;
 463	int  increment=0;
 464	int  n_primary=0;
 465	int  n_steps=0;
 466	int  initial;
 467	int  overflow=0;
 468	int  n_overflow;
 469	int *drops;
 470	short *overflow_tab;
 471	SYLLABLE *syl;
 472
 473	static short continue_tab[5] = {-13, 16, 10, 4, 0};
 474
 475	drops = th->body_drops;
 476
 477	if(continuing)
 478	{
 479		initial =0;
 480		overflow = 0;
 481		n_overflow = 5;
 482		overflow_tab = continue_tab;
 483		increment = (th->body_end - th->body_start) << 8;
 484		increment = increment / (th->body_max_steps -1);
 485	}
 486	else
 487	{
 488		n_overflow = th->n_overflow;
 489		overflow_tab = th->overflow;
 490		initial = 1;
 491	}
 492
 493	while(ix < end_ix)
 494	{
 495		syl = &syllable_tab[ix];
 496		stress = syl->stress;
 497
 498//		if(stress == PRIMARY_MARKED)
 499//			initial = 1;    // reset the intonation pattern
 500
 501		if(initial || (stress >= min_stress))
 502		{
 503			// a primary stress
 504
 505			if((initial) || (stress == 5))
 506			{
 507				initial = 0;
 508				overflow = 0;
 509				n_steps = n_primary = count_increments(ix,end_ix,min_stress);
 510
 511				if(n_steps > th->body_max_steps)
 512					n_steps = th->body_max_steps;
 513
 514				if(n_steps > 1)
 515				{
 516					increment = (th->body_end - th->body_start) << 8;
 517					increment = increment / (n_steps -1);
 518				}
 519				else
 520					increment = 0;
 521
 522				pitch = th->body_start << 8;
 523			}
 524			else
 525			{
 526				if(n_steps > 0)
 527					pitch += increment;
 528				else
 529				{
 530					pitch = (th->body_end << 8) - (increment * overflow_tab[overflow++])/16;
 531					if(overflow >= n_overflow)
 532					{
 533						overflow = 0;
 534						overflow_tab = th->overflow;
 535					}
 536				}
 537			}
 538
 539			n_steps--;
 540
 541			n_primary--;
 542			if((tn->backwards) && (n_primary < 2))
 543			{
 544					pitch = tn->backwards[n_primary] << 8;	
 545			}
 546		}
 547
 548		if(stress >= PRIMARY)
 549		{
 550			syl->stress = PRIMARY_STRESSED;
 551			set_pitch(syl,pitch,drops[stress]);
 552		}
 553		else
 554		if(stress >= SECONDARY)
 555		{
 556			set_pitch(syl,pitch,drops[stress]);
 557		}
 558		else
 559		{
 560			/* unstressed, drop pitch if preceded by PRIMARY */
 561			if((syllable_tab[ix-1].stress & 0x3f) >= SECONDARY)
 562				set_pitch(syl,pitch - (th->body_lower_u << 8), drops[stress]);
 563			else
 564				set_pitch(syl,pitch,drops[stress]);
 565		}
 566
 567		ix++;
 568	}
 569	return(ix);
 570}   /* end of calc_pitch_segment */
 571
 572
 573
 574
 575
 576static int calc_pitch_segment2(int ix, int end_ix, int start_p, int end_p, int min_stress)
 577/****************************************************************************************/
 578/* Linear pitch rise/fall, change pitch at min_stress or stronger
 579	Used for pre-head and tail */
 580{
 581	int  stress;
 582	int  pitch;
 583	int  increment;
 584	int  n_increments;
 585	int  drop;
 586	SYLLABLE *syl;
 587
 588	if(ix >= end_ix)
 589		return(ix);
 590		
 591	n_increments = count_increments(ix,end_ix,min_stress);
 592	increment = (end_p - start_p) << 8;
 593	
 594	if(n_increments > 1)
 595	{
 596		increment = increment / n_increments;
 597	}
 598
 599	
 600	pitch = start_p << 8;
 601	while(ix < end_ix)
 602	{
 603		syl = &syllable_tab[ix];
 604		stress = syl->stress;
 605
 606		if(increment > 0)
 607		{
 608			set_pitch(syl,pitch,-increment);
 609			pitch += increment;
 610		}
 611		else
 612		{
 613			drop = -increment;
 614			if(drop < min_drop[stress])
 615				drop = min_drop[stress];
 616
 617			pitch += increment;
 618
 619			if(drop > 0x900)
 620				drop = 0x900;
 621			set_pitch(syl, pitch, drop);
 622		}
 623			
 624		ix++;
 625	}
 626	return(ix);
 627}   /* end of calc_pitch_segment2 */
 628
 629
 630
 631
 632
 633
 634static int calc_pitches(int start, int end,  int head_tone, int nucleus_tone)
 635//===========================================================================
 636// Calculate pitch values for the vowels in this tone group
 637{
 638	int  ix;
 639	TONE_HEAD *th;
 640	TONE_NUCLEUS *tn;
 641	int  drop;
 642	int continuing = 0;
 643
 644	if(start > 0)
 645		continuing = 1;
 646
 647	th = &tone_head_table[head_tone];
 648	tn = &tone_nucleus_table[nucleus_tone];
 649	ix = start;
 650
 651	/* vowels before the first primary stress */
 652	/******************************************/
 653
 654	if(number_pre > 0)
 655	{
 656		ix = calc_pitch_segment2(ix, ix+number_pre, th->pre_start, th->pre_end, 0);
 657	}
 658
 659	/* body of tonic segment */
 660	/*************************/
 661
 662	if(option_tone_flags & OPTION_EMPHASIZE_PENULTIMATE)
 663	{
 664		tone_posn = tone_posn2;  // put tone on the penultimate stressed word 
 665	}
 666	ix = calc_pitch_segment(ix,tone_posn, th, tn, PRIMARY, continuing);
 667		
 668	if(no_tonic)
 669		return(0);
 670
 671	/* tonic syllable */
 672	/******************/
 673	
 674	if(tn->flags & T_EMPH)
 675	{
 676		syllable_tab[ix].flags |= SYL_EMPHASIS;
 677	}
 678
 679	if(number_tail == 0)
 680	{
 681		tone_pitch_env = tn->pitch_env0;
 682		drop = tn->tonic_max0 - tn->tonic_min0;
 683		set_pitch(&syllable_tab[ix++],tn->tonic_min0 << 8,drop << 8);
 684	}
 685	else
 686	{
 687		tone_pitch_env = tn->pitch_env1;
 688		drop = tn->tonic_max1 - tn->tonic_min1;
 689		set_pitch(&syllable_tab[ix++],tn->tonic_min1 << 8,drop << 8);
 690	}
 691
 692	syllable_tab[tone_posn].env = tone_pitch_env;
 693	if(syllable_tab[tone_posn].stress == PRIMARY)
 694		syllable_tab[tone_posn].stress = PRIMARY_STRESSED;
 695
 696	/* tail, after the tonic syllable */
 697	/**********************************/
 698	
 699	calc_pitch_segment2(ix, end, tn->tail_start, tn->tail_end, 0);
 700
 701	return(tone_pitch_env);
 702}   /* end of calc_pitches */
 703
 704
 705
 706
 707
 708
 709void Translator::CalcPitches_Tone(int clause_tone)
 710{//===============================================
 711//  clause_tone: 0=. 1=, 2=?, 3=! 4=none
 712	PHONEME_LIST *p;
 713	int  ix;
 714	int  count_stressed=0;
 715	int  final_stressed=0;
 716
 717	int  tone_ph;
 718	int pause;
 719	int tone_promoted;
 720	PHONEME_TAB *tph;
 721	PHONEME_TAB *prev_tph;   // forget across word boundary
 722	PHONEME_TAB *prevw_tph;  // remember across word boundary
 723	PHONEME_TAB *prev2_tph;  // 2 tones previous
 724	PHONEME_LIST *prev_p;
 725
 726	int  pitch_adjust = 0;     // pitch gradient through the clause - inital value
 727	int  pitch_decrement = 0;   //   decrease by this for each stressed syllable
 728	int  pitch_low = 0;         //   until it drops to this
 729	int  pitch_high = 0;       //   then reset to this
 730
 731	p = &phoneme_list[0];
 732
 733	// count number of stressed syllables
 734	p = &phoneme_list[0];
 735	for(ix=0; ix<n_phoneme_list; ix++, p++)
 736	{
 737		if((p->type == phVOWEL) && (p->tone >= 4))
 738		{
 739			if(count_stressed == 0)
 740				final_stressed = ix;
 741
 742			if(p->tone >= 4)
 743			{
 744				final_stressed = ix;
 745				count_stressed++;
 746			}
 747		}
 748	}
 749
 750	phoneme_list[final_stressed].tone = 7;
 751
 752	// language specific, changes to tones
 753	if(translator_name == L('v','i'))
 754	{
 755		// LANG=vi
 756		p = &phoneme_list[final_stressed];
 757		if(p->tone_ph == 0)
 758			p->tone_ph = LookupPh("7");   // change tone 1 to falling tone at end of clause
 759	}
 760
 761
 762	pause = 1;
 763	tone_promoted = 0;
 764
 765	prev_p = p = &phoneme_list[0];
 766	prev_tph = prevw_tph = phoneme_tab[phonPAUSE];
 767
 768	// perform tone sandhi
 769	for(ix=0; ix<n_phoneme_list; ix++, p++)
 770	{
 771		if((p->type == phPAUSE) && (p->ph->std_length > 50))
 772		{
 773			pause = 1;  // there is a pause since the previous vowel
 774			prevw_tph = phoneme_tab[phonPAUSE];  // forget previous tone
 775		}
 776
 777		if(p->newword)
 778		{
 779			prev_tph = phoneme_tab[phonPAUSE];  // forget across word boundaries
 780		}
 781
 782		if(p->synthflags & SFLAG_SYLLABLE)
 783		{
 784			tone_ph = p->tone_ph;
 785			tph = phoneme_tab[tone_ph];
 786
 787			// Mandarin
 788			if(translator_name == L('z','h'))
 789			{
 790				if(tone_ph == 0)
 791				{
 792					if(pause || tone_promoted)
 793					{
 794						tone_ph = LookupPh("55");  // no previous vowel, use tone 1
 795						tone_promoted = 1;
 796					}
 797					else
 798					{
 799						tone_ph = LookupPh("11");  // default tone 5
 800					}
 801
 802					p->tone_ph = tone_ph;
 803					tph = phoneme_tab[tone_ph];
 804
 805				}
 806				else
 807				{
 808					tone_promoted = 0;
 809				}
 810
 811				if(ix == final_stressed)
 812				{
 813					if((tph->mnemonic == 0x3535 ) || (tph->mnemonic == 0x3135))
 814					{
 815						// change sentence final tone 1 or 4 to stress 6, not 7
 816						phoneme_list[final_stressed].tone = 6;
 817					}
 818				}
 819
 820				if(prevw_tph->mnemonic == 0x343132)  // [214]
 821				{
 822					if(tph->mnemonic == 0x343132)   // [214]
 823						prev_p->tone_ph = LookupPh("35");
 824					else
 825						prev_p->tone_ph = LookupPh("21"); 
 826				}
 827				if((prev_tph->mnemonic == 0x3135)  && (tph->mnemonic == 0x3135))  //  [51] + [51]
 828				{
 829					prev_p->tone_ph = LookupPh("53");
 830				}
 831
 832				if(tph->mnemonic == 0x3131)  // [11] Tone 5
 833				{
 834					// tone 5, change its level depending on the previous tone (across word boundaries)
 835					if(prevw_tph->mnemonic == 0x3535)
 836						p->tone_ph = LookupPh("22");
 837					if(prevw_tph->mnemonic == 0x3533)
 838						p->tone_ph = LookupPh("33");
 839					if(prevw_tph->mnemonic == 0x343132)
 840						p->tone_ph = LookupPh("44");
 841
 842					// tone 5 is unstressed (shorter)
 843					p->tone = 1;   // diminished stress
 844				}
 845			}
 846
 847			prev_p = p;
 848			prev2_tph = prevw_tph;
 849			prevw_tph = prev_tph = tph;
 850			pause = 0;
 851		}
 852	}
 853
 854	// convert tone numbers to pitch
 855	p = &phoneme_list[0];
 856	for(ix=0; ix<n_phoneme_list; ix++, p++)
 857	{
 858		if(p->synthflags & SFLAG_SYLLABLE)
 859		{
 860			tone_ph = p->tone_ph;
 861
 862			if(p->tone != 1)  // TEST, consider all syllables as stressed
 863			{
 864				if(ix == final_stressed)
 865				{
 866					// the last stressed syllable
 867					pitch_adjust = pitch_low;
 868				}
 869				else
 870				{
 871					pitch_adjust -= pitch_decrement;
 872					if(pitch_adjust <= pitch_low)
 873						pitch_adjust = pitch_high;
 874				}
 875			}
 876
 877			if(tone_ph ==0)
 878			{
 879				tone_ph = phonDEFAULTTONE;  // no tone specified, use default tone 1
 880				p->tone_ph = tone_ph;
 881			}
 882			p->pitch1 = pitch_adjust + phoneme_tab[tone_ph]->start_type;
 883			p->pitch2 = pitch_adjust + phoneme_tab[tone_ph]->end_type;
 884		}
 885	}
 886
 887
 888}  // end of Translator::CalcPitches_Tone
 889
 890
 891
 892void Translator::CalcPitches(int clause_type)
 893{//==========================================
 894//  clause_type: 0=. 1=, 2=?, 3=! 4=none
 895	PHONEME_LIST *p;
 896	SYLLABLE *syl;
 897	int  ix;
 898	int  x;
 899	int  st_ix;
 900	int n_st;
 901	int  option;
 902	int  group_tone;
 903	int  group_tone_emph;
 904	int  group_tone_comma;
 905	int ph_start=0;
 906	int st_start;
 907	int st_clause_end;
 908	int count;
 909	int n_primary;
 910	int count_primary;
 911	PHONEME_TAB *ph;
 912	int ph_end=n_phoneme_list;
 913
 914	SYLLABLE syllable_tab2[N_PHONEME_LIST];
 915
 916	syllable_tab = syllable_tab2;   // don't use permanent storage. it's only needed during the call of CalcPitches()
 917	n_st = 0;
 918	n_primary = 0;
 919	for(ix=0; ix<(n_phoneme_list-1); ix++)
 920	{
 921		p = &phoneme_list[ix];
 922		if(p->synthflags & SFLAG_SYLLABLE)
 923		{
 924			syllable_tab[n_st].flags = 0;
 925			syllable_tab[n_st].env = PITCHfall;
 926			syllable_tab[n_st].nextph_type = phoneme_list[ix+1].type;
 927			syllable_tab[n_st++].stress = p->tone;  // stress level
 928
 929			if(p->tone >= 4)
 930				n_primary++;
 931		}
 932		else
 933		if((p->ph->code == phonPAUSE_CLAUSE) && (n_st > 0))
 934		{
 935			syllable_tab[n_st-1].flags |= SYL_END_CLAUSE;
 936		}
 937	}
 938	syllable_tab[n_st].stress = 0;   // extra 0 entry at the end
 939
 940	if(n_st == 0)
 941		return;  // nothing to do
 942
 943
 944
 945	if(langopts.tone_language == 1)
 946	{
 947		CalcPitches_Tone(clause_type);
 948		return;
 949	}
 950
 951
 952	option = langopts.intonation_group;
 953	if(option >= INTONATION_TYPES)
 954		option = 0;
 955
 956	group_tone = punct_to_tone[option][clause_type]; 
 957	group_tone_emph = punct_to_tone[option][5];   // emphatic form of statement
 958	group_tone_comma = punct_to_tone[option][1];   // emphatic form of statement
 959
 960	if(clause_type == 4)
 961		no_tonic = 1;       /* incomplete clause, used for abbreviations such as Mr. Dr. Mrs. */
 962	else
 963		no_tonic = 0;
 964
 965	st_start = 0;
 966	count_primary=0;
 967	for(st_ix=0; st_ix<n_st; st_ix++)
 968	{
 969		syl = &syllable_tab[st_ix];
 970
 971		if(syl->stress >= 4)
 972			count_primary++;
 973
 974		if(syl->stress == 6)
 975		{
 976			// reduce the stress of the previous stressed syllable (review only the previous few syllables)
 977			for(ix=st_ix-1; ix>=st_start && ix>=(st_ix-3); ix--)
 978			{
 979				if(syllable_tab[ix].stress == 6)
 980					break;
 981				if(syllable_tab[ix].stress == 4)
 982				{
 983					syllable_tab[ix].stress = 3;
 984					break;
 985				}
 986			}
 987
 988			// are the next primary syllables also emphasized ?
 989			for(ix=st_ix+1; ix<n_st; ix++)
 990			{
 991				if(syllable_tab[ix].stress == 4)
 992					break;
 993				if(syllable_tab[ix].stress == 6)
 994				{
 995					// emphasize this syllable, but don't end the current tone group
 996					syllable_tab[st_ix].flags = SYL_EMPHASIS;
 997					syl->stress = 5;
 998					break;
 999				}
1000			}
1001		}
1002
1003		if(syl->stress == 6)
1004		{
1005			// an emphasized syllable, end the tone group after the next primary stress
1006			syllable_tab[st_ix].flags = SYL_EMPHASIS;
1007
1008			count = 0;
1009			if((n_primary - count_primary) > 1)
1010				count =1;
1011
1012			for(ix=st_ix+1; ix<n_st; ix++)
1013			{
1014				if(syllable_tab[ix].stress > 4)
1015					break;
1016				if(syllable_tab[ix].stress == 4)
1017				{
1018					count++;
1019					if(count > 1)
1020						break;
1021				}
1022			}
1023
1024			count_pitch_vowels(st_start, ix, n_st);
1025			if((ix < n_st) || (clause_type == 0))
1026				calc_pitches(st_start, ix, group_tone_emph, group_tone_emph);   // split into > 1 tone groups, use emphatic tone
1027			else
1028				calc_pitches(st_start, ix, group_tone, group_tone);
1029
1030			st_start = ix;
1031		}
1032		if((st_start < st_ix) && (syl->flags & SYL_END_CLAUSE))
1033		{
1034			// end of clause after this syllable, indicated by a phonPAUSE_CLAUSE phoneme
1035			st_clause_end = st_ix+1;
1036			count_pitch_vowels(st_start, st_clause_end, st_clause_end);
1037			calc_pitches(st_start, st_clause_end, group_tone_comma, group_tone_comma);
1038			st_start = st_clause_end;
1039		}
1040	}
1041
1042	if(st_start < st_ix)
1043	{
1044		count_pitch_vowels(st_start, st_ix, n_st);
1045		calc_pitches(st_start, st_ix, group_tone, group_tone);
1046	}
1047
1048	
1049	// unpack pitch data
1050	st_ix=0;
1051	for(ix=ph_start; ix < ph_end; ix++)
1052	{
1053		p = &phoneme_list[ix];
1054		p->tone = syllable_tab[st_ix].stress;
1055		
1056		if(p->synthflags & SFLAG_SYLLABLE)
1057		{
1058			syl = &syllable_tab[st_ix];
1059
1060			x = syl->pitch1 - 72;
1061			if(x < 0) x = 0;
1062			p->pitch1 = x;
1063
1064			x = syl->pitch2 - 72;
1065			if(x < 0) x = 0;
1066			p->pitch2 = x;
1067
1068			p->env = PITCHfall;
1069			if(syl->flags & SYL_RISE)
1070			{
1071				p->env = PITCHrise;
1072			}
1073			else
1074			if(p->tone > 5)
1075				p->env = syl->env;
1076
1077			if(p->pitch1 > p->pitch2)
1078			{
1079				// swap so that pitch2 is the higher
1080				x = p->pitch1;
1081				p->pitch1 = p->pitch2;
1082				p->pitch2 = x;
1083			}
1084
1085if(p->tone_ph)
1086{
1087	ph = phoneme_tab[p->tone_ph];
1088	x = (p->pitch1 + p->pitch2)/2;
1089	p->pitch2 = x + ph->end_type;
1090	p->pitch1 = x + ph->start_type;
1091}
1092
1093			if(syl->flags & SYL_EMPHASIS)
1094			{
1095				p->tone |= 8;      // emphasized
1096			}
1097	
1098			st_ix++;
1099		}
1100	}
1101
1102}  // end of Translator::CalcPitches
1103
1104