]> git.mxchange.org Git - flightgear.git/blob - 3rdparty/flite_hts_engine/lib/flite_hts_engine.c
Render voice to memory, no more temp files.
[flightgear.git] / 3rdparty / flite_hts_engine / lib / flite_hts_engine.c
1 /* ----------------------------------------------------------------- */
2 /*           The English TTS System "Flite+hts_engine"               */
3 /*           developed by HTS Working Group                          */
4 /*           http://hts-engine.sourceforge.net/                      */
5 /* ----------------------------------------------------------------- */
6 /*                                                                   */
7 /*  Copyright (c) 2005-2013  Nagoya Institute of Technology          */
8 /*                           Department of Computer Science          */
9 /*                                                                   */
10 /*                2005-2008  Tokyo Institute of Technology           */
11 /*                           Interdisciplinary Graduate School of    */
12 /*                           Science and Engineering                 */
13 /*                                                                   */
14 /* All rights reserved.                                              */
15 /*                                                                   */
16 /* Redistribution and use in source and binary forms, with or        */
17 /* without modification, are permitted provided that the following   */
18 /* conditions are met:                                               */
19 /*                                                                   */
20 /* - Redistributions of source code must retain the above copyright  */
21 /*   notice, this list of conditions and the following disclaimer.   */
22 /* - Redistributions in binary form must reproduce the above         */
23 /*   copyright notice, this list of conditions and the following     */
24 /*   disclaimer in the documentation and/or other materials provided */
25 /*   with the distribution.                                          */
26 /* - Neither the name of the HTS working group nor the names of its  */
27 /*   contributors may be used to endorse or promote products derived */
28 /*   from this software without specific prior written permission.   */
29 /*                                                                   */
30 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND            */
31 /* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,       */
32 /* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF          */
33 /* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE          */
34 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS */
35 /* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          */
36 /* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
37 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     */
38 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
39 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,   */
40 /* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY    */
41 /* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
42 /* POSSIBILITY OF SUCH DAMAGE.                                       */
43 /* ----------------------------------------------------------------- */
44
45 #include "cst_synth.h"
46 #include "cst_utt_utils.h"
47 #include "cst_math.h"
48 #include "cst_file.h"
49 #include "cst_val.h"
50 #include "cst_string.h"
51 #include "cst_alloc.h"
52 #include "cst_item.h"
53 #include "cst_relation.h"
54 #include "cst_utterance.h"
55 #include "cst_tokenstream.h"
56 #include "cst_string.h"
57 #include "cst_regex.h"
58 #include "cst_features.h"
59 #include "cst_utterance.h"
60 #include "flite.h"
61 #include "cst_synth.h"
62 #include "cst_utt_utils.h"
63
64 #include "flite_hts_engine.h"
65
66 /* HTS_GStreamSet_get_total_nsamples: get total number of sample */
67 size_t HTS_GStreamSet_get_total_nsamples(HTS_GStreamSet * gss);
68
69 /* HTS_GStreamSet_get_speech: get synthesized speech parameter */
70 double HTS_GStreamSet_get_speech(HTS_GStreamSet * gss, size_t sample_index);
71
72 #define REGISTER_VOX register_cmu_us_kal
73 #define UNREGISTER_VOX unregister_cmu_us_kal
74
75 #define MAXBUFLEN 1024
76
77 cst_voice *REGISTER_VOX(const char *voxdir);
78 cst_voice *UNREGISTER_VOX(cst_voice * vox);
79
80 /* Flite_HTS_Engine_create_label: create label per phoneme */
81 static void Flite_HTS_Engine_create_label(Flite_HTS_Engine * f, cst_item * item, char *label)
82 {
83    char seg_pp[8];
84    char seg_p[8];
85    char seg_c[8];
86    char seg_n[8];
87    char seg_nn[8];
88    char endtone[8];
89    int sub_phrases = 0;
90    int lisp_total_phrases = 0;
91    int tmp1 = 0;
92    int tmp2 = 0;
93    int tmp3 = 0;
94    int tmp4 = 0;
95
96    /* load segments */
97    strcpy(seg_pp, ffeature_string(item, "p.p.name"));
98    strcpy(seg_p, ffeature_string(item, "p.name"));
99    strcpy(seg_c, ffeature_string(item, "name"));
100    strcpy(seg_n, ffeature_string(item, "n.name"));
101    strcpy(seg_nn, ffeature_string(item, "n.n.name"));
102
103    /* load endtone */
104    strcpy(endtone, ffeature_string(item, "R:SylStructure.parent.parent.R:Phrase.parent.daughtern.R:SylStructure.daughtern.endtone"));
105
106    if (strcmp(seg_c, "pau") == 0) {
107       /* for pause */
108       if (item_next(item) != NULL) {
109          sub_phrases = ffeature_int(item, "n.R:SylStructure.parent.R:Syllable.sub_phrases");
110          tmp1 = ffeature_int(item, "n.R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_syls");
111          tmp2 = ffeature_int(item, "n.R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_words");
112          lisp_total_phrases = ffeature_int(item, "n.R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_phrases");
113       } else {
114          sub_phrases = ffeature_int(item, "p.R:SylStructure.parent.R:Syllable.sub_phrases");
115          tmp1 = ffeature_int(item, "p.R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_syls");
116          tmp2 = ffeature_int(item, "p.R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_words");
117          lisp_total_phrases = ffeature_int(item, "p.R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_phrases");
118       }
119       sprintf(label, "%s^%s-%s+%s=%s@x_x/A:%d_%d_%d/B:x-x-x@x-x&x-x#x-x$x-x!x-x;x-x|x/C:%d+%d+%d/D:%s_%d/E:x+x@x+x&x+x#x+x/F:%s_%d/G:%d_%d/H:x=x^%d=%d|%s/I:%d=%d/J:%d+%d-%d", strcmp(seg_pp, "0") == 0 ? "x" : seg_pp, strcmp(seg_p, "0") == 0 ? "x" : seg_p, seg_c, strcmp(seg_n, "0") == 0 ? "x" : seg_n, strcmp(seg_nn, "0") == 0 ? "x" : seg_nn, ffeature_int(item, "p.R:SylStructure.parent.R:Syllable.stress"), ffeature_int(item, "p.R:SylStructure.parent.R:Syllable.accented"), ffeature_int(item, "p.R:SylStructure.parent.R:Syllable.syl_numphones"), ffeature_int(item, "n.R:SylStructure.parent.R:Syllable.stress"), ffeature_int(item, "n.R:SylStructure.parent.R:Syllable.accented"), ffeature_int(item, "n.R:SylStructure.parent.R:Syllable.syl_numphones"), ffeature_string(item, "p.R:SylStructure.parent.parent.R:Word.gpos"), ffeature_int(item, "p.R:SylStructure.parent.parent.R:Word.word_numsyls"), ffeature_string(item, "n.R:SylStructure.parent.parent.R:Word.gpos"), ffeature_int(item, "n.R:SylStructure.parent.parent.R:Word.word_numsyls"), ffeature_int(item, "p.R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_syls_in_phrase"), ffeature_int(item, "p.R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_words_in_phrase"), sub_phrases + 1, lisp_total_phrases - sub_phrases, endtone, ffeature_int(item, "n.R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_syls_in_phrase"), ffeature_int(item, "n.R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_words_in_phrase"), tmp1, tmp2, lisp_total_phrases);
120    } else {
121       /* for no pause */
122       tmp1 = ffeature_int(item, "R:SylStructure.pos_in_syl");
123       tmp2 = ffeature_int(item, "R:SylStructure.parent.R:Syllable.syl_numphones");
124       tmp3 = ffeature_int(item, "R:SylStructure.parent.R:Syllable.pos_in_word");
125       tmp4 = ffeature_int(item, "R:SylStructure.parent.parent.R:Word.word_numsyls");
126       sub_phrases = ffeature_int(item, "R:SylStructure.parent.R:Syllable.sub_phrases");
127       lisp_total_phrases = ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_phrases");
128       sprintf(label, "%s^%s-%s+%s=%s@%d_%d/A:%d_%d_%d/B:%d-%d-%d@%d-%d&%d-%d#%d-%d$%d-%d!%d-%d;%d-%d|%s/C:%d+%d+%d/D:%s_%d/E:%s+%d@%d+%d&%d+%d#%d+%d/F:%s_%d/G:%d_%d/H:%d=%d^%d=%d|%s/I:%d=%d/J:%d+%d-%d", strcmp(seg_pp, "0") == 0 ? "x" : seg_pp, strcmp(seg_p, "0") == 0 ? "x" : seg_p, seg_c, strcmp(seg_n, "0") == 0 ? "x" : seg_n, strcmp(seg_nn, "0") == 0 ? "x" : seg_nn, tmp1 + 1, tmp2 - tmp1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.p.stress"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.p.accented"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.p.syl_numphones"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.stress"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.accented"), tmp2, tmp3 + 1, tmp4 - tmp3, ffeature_int(item, "R:SylStructure.parent.R:Syllable.syl_in") + 1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.syl_out") + 1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.ssyl_in") + 1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.ssyl_out") + 1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.asyl_in") + 1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.asyl_out") + 1, ffeature_int(item, "R:SylStructure.parent.R:Syllable.lisp_distance_to_p_stress"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.lisp_distance_to_n_stress"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.lisp_distance_to_p_accent"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.lisp_distance_to_n_accent"), ffeature_string(item, "R:SylStructure.parent.R:Syllable.syl_vowel"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.n.stress"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.n.accented"), ffeature_int(item, "R:SylStructure.parent.R:Syllable.n.syl_numphones"), ffeature_string(item, "R:SylStructure.parent.parent.R:Word.p.gpos"), ffeature_int(item, "R:SylStructure.parent.parent.R:Word.p.word_numsyls"), ffeature_string(item, "R:SylStructure.parent.parent.R:Word.gpos"), tmp4, ffeature_int(item, "R:SylStructure.parent.parent.R:Word.pos_in_phrase") + 1, ffeature_int(item, "R:SylStructure.parent.parent.R:Word.words_out"), ffeature_int(item, "R:SylStructure.parent.parent.R:Word.content_words_in") + 1, ffeature_int(item, "R:SylStructure.parent.parent.R:Word.content_words_out") + 1, ffeature_int(item, "R:SylStructure.parent.parent.R:Word.lisp_distance_to_p_content"), ffeature_int(item, "R:SylStructure.parent.parent.R:Word.lisp_distance_to_n_content"), ffeature_string(item, "R:SylStructure.parent.parent.R:Word.n.gpos"), ffeature_int(item, "R:SylStructure.parent.parent.R:Word.n.word_numsyls"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.p.lisp_num_syls_in_phrase"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.p.lisp_num_words_in_phrase"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_syls_in_phrase"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_words_in_phrase"), sub_phrases + 1, lisp_total_phrases - sub_phrases, strcmp(endtone, "0") == 0 ? "NONE" : endtone, ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.n.lisp_num_syls_in_phrase"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.n.lisp_num_words_in_phrase"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_syls"), ffeature_int(item, "R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_words"), lisp_total_phrases);
129    }
130 }
131
132 /* Flite_HTS_Engine_initialize: initialize system */
133 void Flite_HTS_Engine_initialize(Flite_HTS_Engine * f)
134 {
135    HTS_Engine_initialize(&f->engine);
136 }
137
138 /* Flite_HTS_Engine_load: load HTS voice */
139 HTS_Boolean Flite_HTS_Engine_load(Flite_HTS_Engine * f, const char *fn)
140 {
141    HTS_Boolean result;
142    char *voices = strdup(fn);
143    result = HTS_Engine_load(&f->engine, &voices, 1);
144    free(voices);
145    return result;
146 }
147
148 /* Flite_HTS_Engine_set_sampling_frequency: set sampling frequency */
149 void Flite_HTS_Engine_set_sampling_frequency(Flite_HTS_Engine * f, size_t i)
150 {
151    HTS_Engine_set_sampling_frequency(&f->engine, i);
152 }
153
154 /* Flite_HTS_Engine_set_fperiod: set frame period */
155 void Flite_HTS_Engine_set_fperiod(Flite_HTS_Engine * f, size_t i)
156 {
157    HTS_Engine_set_fperiod(&f->engine, i);
158 }
159
160 /* Flite_HTS_Engine_set_audio_buff_size: set audio buffer size */
161 void Flite_HTS_Engine_set_audio_buff_size(Flite_HTS_Engine * f, size_t i)
162 {
163    HTS_Engine_set_audio_buff_size(&f->engine, i);
164 }
165
166 /* Flite_HTS_Engine_set_alpha: set alpha */
167 void Flite_HTS_Engine_set_alpha(Flite_HTS_Engine * f, double d)
168 {
169    HTS_Engine_set_alpha(&f->engine, d);
170 }
171
172 /* Flite_HTS_Engine_set_beta: set beta */
173 void Flite_HTS_Engine_set_beta(Flite_HTS_Engine * f, double d)
174 {
175    HTS_Engine_set_beta(&f->engine, d);
176 }
177
178 /* Flite_HTS_Engine_add_half_tone: add half-tone */
179 void Flite_HTS_Engine_add_half_tone(Flite_HTS_Engine * f, double d)
180 {
181    HTS_Engine_add_half_tone(&f->engine, d);
182 }
183
184 /* Flite_HTS_Engine_set_msd_threshold: set MSD threshold */
185 void Flite_HTS_Engine_set_msd_threshold(Flite_HTS_Engine * f, size_t stream_index, double d)
186 {
187    HTS_Engine_set_msd_threshold(&f->engine, stream_index, d);
188 }
189
190 /* Flite_HTS_Engine_set_gv_weight: set GV weight */
191 void Flite_HTS_Engine_set_gv_weight(Flite_HTS_Engine * f, size_t stream_index, double d)
192 {
193    HTS_Engine_set_gv_weight(&f->engine, stream_index, d);
194 }
195
196 /* Flite_HTS_Engine_set_speed: set speech speed */
197 void Flite_HTS_Engine_set_speed(Flite_HTS_Engine * f, double d)
198 {
199    HTS_Engine_set_speed(&f->engine, d);
200 }
201
202 /* Flite_HTS_Engine_synthesize: synthesize speech */
203 HTS_Boolean Flite_HTS_Engine_synthesize(Flite_HTS_Engine * f, const char *txt, const char *wav)
204 {
205    int i;
206    FILE *fp;
207    cst_voice *v = NULL;
208    cst_utterance *u = NULL;
209    cst_item *s = NULL;
210    char **label_data = NULL;
211    int label_size = 0;
212
213    if (txt == NULL)
214       return FALSE;
215
216    /* text analysis part */
217    v = REGISTER_VOX(NULL);
218    if (v == NULL)
219       return FALSE;
220    u = flite_synth_text(txt, v);
221    if (u == NULL)
222       return FALSE;
223    for (s = relation_head(utt_relation(u, "Segment")); s; s = item_next(s))
224       label_size++;
225    if (label_size <= 0)
226       return FALSE;
227    label_data = (char **) calloc(label_size, sizeof(char *));
228    for (i = 0, s = relation_head(utt_relation(u, "Segment")); s; s = item_next(s), i++) {
229       label_data[i] = (char *) calloc(MAXBUFLEN, sizeof(char));
230       Flite_HTS_Engine_create_label(f, s, label_data[i]);
231    }
232
233    /* speech synthesis part */
234    HTS_Engine_synthesize_from_strings(&f->engine, label_data, label_size);
235    if (wav != NULL) {
236       fp = fopen(wav, "wb");
237       HTS_Engine_save_riff(&f->engine, fp);
238       fclose(fp);
239    }
240    HTS_Engine_refresh(&f->engine);
241
242    for (i = 0; i < label_size; i++)
243       free(label_data[i]);
244    free(label_data);
245
246    delete_utterance(u);
247    UNREGISTER_VOX(v);
248
249    return TRUE;
250 }
251
252 /* Flite_HTS_Engine_synthesize: synthesize speech */
253 HTS_Boolean Flite_HTS_Engine_synthesize_samples_mono16(Flite_HTS_Engine * f, const char *txt,
254                                                 void** samples, int* sampleCount, int* sampleRate)
255 {
256     int i;
257     cst_voice *v = NULL;
258     cst_utterance *u = NULL;
259     cst_item *s = NULL;
260     char **label_data = NULL;
261     int label_size = 0;
262     short* samplePtr = NULL;
263     HTS_GStreamSet *gss;
264     
265     if (txt == NULL)
266         return FALSE;
267     
268     /* text analysis part */
269     v = REGISTER_VOX(NULL);
270     if (v == NULL)
271         return FALSE;
272     u = flite_synth_text(txt, v);
273     if (u == NULL)
274         return FALSE;
275     for (s = relation_head(utt_relation(u, "Segment")); s; s = item_next(s))
276         label_size++;
277     if (label_size <= 0)
278         return FALSE;
279     label_data = (char **) calloc(label_size, sizeof(char *));
280     for (i = 0, s = relation_head(utt_relation(u, "Segment")); s; s = item_next(s), i++) {
281         label_data[i] = (char *) calloc(MAXBUFLEN, sizeof(char));
282         Flite_HTS_Engine_create_label(f, s, label_data[i]);
283     }
284     
285     /* speech synthesis part */
286     HTS_Engine_synthesize_from_strings(&f->engine, label_data, label_size);
287     
288     gss = &f->engine.gss;
289     *sampleRate = f->engine.condition.sampling_frequency;
290     *sampleCount = HTS_GStreamSet_get_total_nsamples(gss);
291     *samples = malloc(sizeof(short) * *sampleCount);
292     samplePtr = *samples;
293     
294     for (i=0; i < *sampleCount; ++i) {
295         *samplePtr++ = (short) HTS_GStreamSet_get_speech(gss, i);
296     }
297     
298     HTS_Engine_refresh(&f->engine);
299     
300     for (i = 0; i < label_size; i++)
301         free(label_data[i]);
302     free(label_data);
303     
304     delete_utterance(u);
305     UNREGISTER_VOX(v);
306     
307     return TRUE;
308 }
309
310
311 /* Flite_HTS_Engine_clear: free system */
312 void Flite_HTS_Engine_clear(Flite_HTS_Engine * f)
313 {
314    HTS_Engine_clear(&f->engine);
315 }
316
317 typedef struct _Flite_Utterance {
318    cst_voice *v;
319    cst_utterance *u;
320    int nitem;
321    cst_item **items;
322 } Flite_Utterance;
323
324 /* Flite_Text_Analyzer_initialize: initialize flite front-end */
325 void Flite_Text_Analyzer_initialize(Flite_Text_Analyzer * analyzer)
326 {
327    if (analyzer == NULL)
328       return;
329    analyzer->pointer = NULL;
330 }
331
332 /* Flite_Text_Analyzer_analysis: text analysis */
333 void Flite_Text_Analyzer_analysis(Flite_Text_Analyzer * analyzer, const char *text)
334 {
335    int i;
336    cst_item *s;
337    Flite_Utterance *fu;
338
339    if (analyzer == NULL || text == NULL)
340       return;
341
342    if (analyzer->pointer != NULL)
343       Flite_Text_Analyzer_clear(analyzer);
344
345    /* allocate */
346    fu = (Flite_Utterance *) malloc(sizeof(Flite_Utterance));
347
348    /* create voice */
349    fu->v = REGISTER_VOX(NULL);
350    if (fu->v == NULL) {
351       free(fu);
352       return;
353    }
354
355    /* create utterance */
356    fu->u = flite_synth_text(text, fu->v);
357    if (fu->u == NULL) {
358       UNREGISTER_VOX(fu->v);
359       free(fu);
360       return;
361    }
362
363    /* count number of phonemes */
364    for (fu->nitem = 0, s = relation_head(utt_relation(fu->u, "Segment")); s; s = item_next(s), fu->nitem++);
365    if (fu->nitem == 0) {
366       delete_utterance(fu->u);
367       UNREGISTER_VOX(fu->v);
368       free(fu);
369       return;
370    }
371
372    /* save informations */
373    fu->items = (cst_item **) malloc(sizeof(cst_item *) * fu->nitem);
374    for (i = 0, s = relation_head(utt_relation(fu->u, "Segment")); s; s = item_next(s), i++)
375       fu->items[i] = s;
376
377    analyzer->pointer = (void *) fu;
378 }
379
380 /* Flite_Text_Analyzer_get_nphoneme_in_utterance: get number of phonemes */
381 int Flite_Text_Analyzer_get_nphoneme_in_utterance(Flite_Text_Analyzer * analyzer)
382 {
383    Flite_Utterance *fu;
384
385    if (analyzer == NULL || analyzer->pointer == NULL)
386       return 0;
387
388    fu = (Flite_Utterance *) analyzer->pointer;
389    return fu->nitem;
390 }
391
392 /* Flite_Text_Analyzer_get_phoneme: get phoneme identity */
393 const char *Flite_Text_Analyzer_get_phoneme(Flite_Text_Analyzer * analyzer, int phoneme_index)
394 {
395    Flite_Utterance *fu;
396
397    if (analyzer == NULL || analyzer->pointer == NULL)
398       return NULL;
399    fu = (Flite_Utterance *) analyzer->pointer;
400    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
401       return NULL;
402    return ffeature_string(fu->items[phoneme_index], "name");
403 }
404
405 /* Flite_Text_Analyzer_get_word: get word */
406 const char *Flite_Text_Analyzer_get_word(Flite_Text_Analyzer * analyzer, int phoneme_index)
407 {
408    Flite_Utterance *fu;
409
410    if (analyzer == NULL || analyzer->pointer == NULL)
411       return NULL;
412    fu = (Flite_Utterance *) analyzer->pointer;
413    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
414       return NULL;
415    return ffeature_string(fu->items[phoneme_index], "R:SylStructure.parent.parent.name");
416 }
417
418 /* Flite_Text_Analyzer_get_nphoneme_in_syllable: get number of phonemes in syllable */
419 int Flite_Text_Analyzer_get_nphoneme_in_syllable(Flite_Text_Analyzer * analyzer, int phoneme_index)
420 {
421    Flite_Utterance *fu;
422
423    if (analyzer == NULL || analyzer->pointer == NULL)
424       return 0;
425    fu = (Flite_Utterance *) analyzer->pointer;
426    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
427       return 0;
428    return ffeature_int(fu->items[phoneme_index], "R:SylStructure.parent.R:Syllable.syl_numphones");
429 }
430
431 /* Flite_Text_Analayzer_get_nsyllable_in_word: get number of syllables in word */
432 int Flite_Text_Analyzer_get_nsyllable_in_word(Flite_Text_Analyzer * analyzer, int phoneme_index)
433 {
434    Flite_Utterance *fu;
435
436    if (analyzer == NULL || analyzer->pointer == NULL)
437       return 0;
438    fu = (Flite_Utterance *) analyzer->pointer;
439    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
440       return 0;
441    return ffeature_int(fu->items[phoneme_index], "R:SylStructure.parent.parent.R:Word.word_numsyls");
442 }
443
444 /* Flite_Text_Analyzer_get_nword_in_phrase: get number of words in phrase */
445 int Flite_Text_Analyzer_get_nword_in_phrase(Flite_Text_Analyzer * analyzer, int phoneme_index)
446 {
447    Flite_Utterance *fu;
448
449    if (analyzer == NULL || analyzer->pointer == NULL)
450       return 0;
451    fu = (Flite_Utterance *) analyzer->pointer;
452    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
453       return 0;
454    return ffeature_int(fu->items[phoneme_index], "R:SylStructure.parent.parent.R:Phrase.parent.lisp_num_words_in_phrase");
455 }
456
457 /* Flite_Text_Analyzer_get_nphrase_in_utterance: get number of phrases in utterance */
458 int Flite_Text_Analyzer_get_nphrase_in_utterance(Flite_Text_Analyzer * analyzer, int phoneme_index)
459 {
460    Flite_Utterance *fu;
461
462    if (analyzer == NULL || analyzer->pointer == NULL)
463       return 0;
464    fu = (Flite_Utterance *) analyzer->pointer;
465    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
466       return 0;
467    return ffeature_int(fu->items[phoneme_index], "R:SylStructure.parent.parent.R:Phrase.parent.lisp_total_phrases");
468 }
469
470 /* Flite_Text_Analyzer_get_accent: get accent */
471 int Flite_Text_Analyzer_get_accent(Flite_Text_Analyzer * analyzer, int phoneme_index)
472 {
473    Flite_Utterance *fu;
474
475    if (analyzer == NULL || analyzer->pointer == NULL)
476       return 0;
477    fu = (Flite_Utterance *) analyzer->pointer;
478    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
479       return 0;
480    return ffeature_int(fu->items[phoneme_index], "R:SylStructure.parent.R:Syllable.accented");
481 }
482
483 /* Flite_Text_Analyzer_get_stress: get stress */
484 int Flite_Text_Analyzer_get_stress(Flite_Text_Analyzer * analyzer, int phoneme_index)
485 {
486    Flite_Utterance *fu;
487
488    if (analyzer == NULL || analyzer->pointer == NULL)
489       return 0;
490    fu = (Flite_Utterance *) analyzer->pointer;
491    if (phoneme_index < 0 || phoneme_index >= fu->nitem)
492       return 0;
493    return ffeature_int(fu->items[phoneme_index], "R:SylStructure.parent.R:Syllable.stress");
494 }
495
496 /* Flite_Text_Analyzer_clear: finalize flite front-end */
497 void Flite_Text_Analyzer_clear(Flite_Text_Analyzer * analyzer)
498 {
499    Flite_Utterance *fu;
500
501    if (analyzer == NULL || analyzer->pointer == NULL)
502       return;
503
504    fu = (Flite_Utterance *) analyzer->pointer;
505    if (fu->items != NULL)
506       free(fu->items);
507    if (fu->u != NULL)
508       delete_utterance(fu->u);
509    if (fu->v != NULL)
510       UNREGISTER_VOX(fu->v);
511    free(fu);
512
513    analyzer->pointer = NULL;
514 }