1 /* Copyright (C) 2012, 2013, 2014, 2018, 2019  Olga Yakovleva <yakovleva.o.v@gmail.com> */
2 
3 /* This program is free software: you can redistribute it and/or modify */
4 /* it under the terms of the GNU Lesser General Public License as published by */
5 /* the Free Software Foundation, either version 2.1 of the License, or */
6 /* (at your option) any later version. */
7 
8 /* This program is distributed in the hope that it will be useful, */
9 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
10 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
11 /* GNU Lesser General Public License for more details. */
12 
13 /* You should have received a copy of the GNU Lesser General Public License */
14 /* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
15 
16 #ifndef RHVOICE_LANGUAGE_HPP
17 #define RHVOICE_LANGUAGE_HPP
18 
19 #include <string>
20 #include <vector>
21 #include <map>
22 #include <set>
23 #include <memory>
24 #include "params.hpp"
25 #include "exception.hpp"
26 
27 #include "path.hpp"
28 #include "resource.hpp"
29 #include "value.hpp"
30 #include "utterance.hpp"
31 #include "relation.hpp"
32 #include "phoneme_set.hpp"
33 #include "hts_labeller.hpp"
34 #include "fst.hpp"
35 #include "dtree.hpp"
36 #include "userdict.hpp"
37 #include "str.hpp"
38 #include "pitch.hpp"
39 
40 namespace RHVoice
41 {
42   class utterance;
43   class item;
44   class language_info;
45   class language_list;
46 
47   enum verbosity_flag
48     {
49       verbosity_silent=0,
50       verbosity_name=1,
51       verbosity_full_name=2,
52       verbosity_spell=4,
53       verbosity_pitch=8,
54       verbosity_sound=16
55     };
56   typedef unsigned int verbosity_t;
57 
58   enum break_strength
59     {
60       break_default,
61       break_none,
62       break_phrase,
63       break_sentence
64     };
65 
66   class feature_function_not_found: public lookup_error
67   {
68   public:
feature_function_not_found()69     feature_function_not_found():
70       lookup_error("Feature function not found")
71     {
72     }
73   };
74 
75   class feature_function
76   {
77   public:
~feature_function()78     virtual ~feature_function()
79     {
80     }
81 
get_name() const82     const std::string& get_name() const
83     {
84       return name;
85     }
86 
87     value virtual eval(const item& i) const=0;
88 
89   protected:
feature_function(const std::string & name_)90     explicit feature_function(const std::string& name_):
91       name(name_)
92     {
93     }
94 
95   private:
96     feature_function(const feature_function&);
97     feature_function& operator=(const feature_function&);
98 
99     const std::string name;
100   };
101 
102   class language_error: public exception
103   {
104   public:
language_error(const std::string & msg)105     explicit language_error(const std::string& msg):
106       exception(msg)
107     {
108     }
109   };
110 
111   class tokenization_error: public language_error
112   {
113   public:
tokenization_error()114     tokenization_error():
115       language_error("Tokenization failed")
116     {
117     }
118   };
119 
120   class g2p_error: public language_error
121   {
122   public:
g2p_error(const item & word)123     g2p_error(const item& word):
124       language_error("G2p failed: "+word.get("name").as<std::string>())
125     {
126     }
127   };
128 
129     class syllabification_error: public language_error
130     {
131     public:
syllabification_error()132       syllabification_error():
133         language_error("Syllabification failed")
134       {
135       }
136     };
137 
138     class fst_error: public language_error
139     {
140     public:
fst_error()141       fst_error():
142         language_error("Unexpected fst output")
143       {
144       }
145     };
146 
147   class language
148   {
149   public:
~language()150     virtual ~language()
151     {
152     }
153 
154     virtual const language_info& get_info() const=0;
155 
get_feature_function(const std::string & name) const156     const feature_function& get_feature_function(const std::string& name) const
157     {
158       std::map<std::string,std::shared_ptr<feature_function> >::const_iterator it(feature_functions.find(name));
159       if(it==feature_functions.end())
160         throw feature_function_not_found();
161       else
162         return *(it->second);
163     }
164 
get_feature_function_ptr(const std::string & name) const165     const feature_function* get_feature_function_ptr(const std::string& name) const
166     {
167       std::map<std::string,std::shared_ptr<feature_function> >::const_iterator it(feature_functions.find(name));
168       if(it==feature_functions.end())
169         return 0;
170       else
171         return (it->second.get());
172     }
173 
get_hts_labeller() const174     const hts_labeller& get_hts_labeller() const
175     {
176       return labeller;
177     }
178 
get_phoneme_set() const179     const phoneme_set& get_phoneme_set() const
180     {
181       return phonemes;
182     }
183 
184     item& append_token(utterance& u,const std::string& text) const;
185 
supports_emoji() const186     bool supports_emoji() const
187     {
188       return (emoji_fst.get()!=0);
189 }
190 
191     item& append_emoji(utterance& u,const std::string& text) const;
192     void do_text_analysis(utterance& u) const;
193     void do_pos_tagging(utterance& u) const;
194     void phrasify(utterance& u) const;
195     void detect_utt_type(utterance& u) const;
196     void do_g2p(utterance& u) const;
197     void syllabify(utterance& u) const;
198     void insert_pauses(utterance& u) const;
199     void do_post_lexical_processing(utterance& u) const;
200     void set_pitch_modifications(utterance& u) const;
201     void set_duration_modifications(utterance& u) const;
202     void stress_monosyllabic_words(utterance& u) const;
203     void rename_palatalized_consonants(utterance& u) const;
204 
205     virtual void decode_as_word(item& token,const std::string& name) const;
206     virtual void decode_as_letter_sequence(item& token,const std::string& name) const;
207 
208     virtual std::vector<std::string> get_word_transcription(const item& word) const=0;
209 
210     template<typename forward_iterator,typename output_iterator>
downcase(forward_iterator first,forward_iterator last,output_iterator output) const211     void downcase(forward_iterator first,forward_iterator last,output_iterator output) const
212     {
213       downcase_fst.translate(first,last,output);
214     }
215 
216   protected:
217     explicit language(const language_info& info_);
218 
register_feature(const std::shared_ptr<feature_function> & f)219     void register_feature(const std::shared_ptr<feature_function>& f)
220     {
221       feature_functions[f->get_name()]=f;
222     }
223 
get_hts_labeller()224     hts_labeller& get_hts_labeller()
225     {
226       return labeller;
227     }
228 
229     virtual bool decode_as_known_character(item& token,const std::string& name) const;
230 
231     virtual void assign_pronunciation(item& word) const;
232 
233   private:
234     language(const language&);
235     language& operator=(const language&);
236 
237     void register_default_features();
238 
post_lex(utterance & u) const239     virtual void post_lex(utterance& u) const
240     {
241     }
242 
243     void decode(item& token) const;
244     void default_decode_as_word(item& token,const std::string& name) const;
245     void decode_as_number(item& token,const std::string& name) const;
246     void decode_as_digit_string(item& token,const std::string& name) const;
247     void decode_as_unknown_character(item& token,const std::string& name) const;
248     void decode_as_character(item& token,const std::string& name) const;
249     void decode_as_key(item& token,const std::string& name) const;
250 
decode_as_special_symbol(item & token,const std::string & name,const std::string & type) const251     virtual void decode_as_special_symbol(item& token,const std::string& name,const std::string& type) const
252     {
253     }
254 
255     void indicate_case_if_necessary(item& token) const;
256     break_strength get_word_break(const item& word) const;
257     bool should_break_emoji(const item& word) const;
258     bool decode_as_english(item& tok) const;
259     std::vector<std::string> get_english_word_transcription(const item& word) const;
260 
before_g2p(item & word) const261     virtual void before_g2p(item& word) const
262 {
263 }
264     bool check_for_f123(const item& tok,const std::string& name) const;
265 
266     bool translate_emoji(item& token,std::vector<utf8::uint32_t>::const_iterator start,std::vector<utf8::uint32_t>::const_iterator end) const;
267     std::vector<utf8::uint32_t> remove_emoji_presentation_selectors(const std::string& text) const;
268     void translate_emoji_element(item& token,std::vector<utf8::uint32_t>::const_iterator start,std::vector<utf8::uint32_t>::const_iterator end) const;
269     void translate_emoji_sequence(item& token,const std::string& text) const;
270 
271 
272     std::map<std::string,std::shared_ptr<feature_function> > feature_functions;
273     const phoneme_set phonemes;
274     hts_labeller labeller;
275     const fst tok_fst;
276     const fst key_fst;
277     const fst numbers_fst;
278     const fst gpos_fst;
279     const dtree phrasing_dtree;
280     const fst syl_fst;
281     std::vector<std::string> msg_cap_letter,msg_char_code;
282     std::map<utf8::uint32_t,std::string> whitespace_symbols;
283     std::unique_ptr<fst> english_phone_mapping_fst;
284     std::unique_ptr<fst> emoji_fst;
285 std::unique_ptr<fst> qst_fst;
286     std::unique_ptr<dtree> pitch_mod_dtree;
287     std::unique_ptr<dtree> dur_mod_dtree;
288     pitch::targets_spec_parser pts_parser;
289     userdict::dict udict;
290 
291   protected:
292     const fst spell_fst;
293     const fst downcase_fst;
294   };
295 
296   class language_info: public resource_info<language>
297   {
298     friend class language_list;
299   protected:
300     language_info(const std::string& name,const std::string& data_path,const std::string& userdict_path);
301 
set_alpha2_code(const std::string & code)302     void set_alpha2_code(const std::string& code)
303     {
304       alpha2_code=code;
305     }
306 
set_alpha3_code(const std::string & code)307     void set_alpha3_code(const std::string& code)
308     {
309       alpha3_code=code;
310     }
311 
312   public:
313     voice_params voice_settings;
314     text_params text_settings;
315     bool_property use_pseudo_english;
316 
317     void register_settings(config& cfg);
318 
is_enabled() const319     bool is_enabled() const
320     {
321       return enabled;
322     }
323 
is_letter(utf8::uint32_t cp) const324     bool is_letter(utf8::uint32_t cp) const
325     {
326       return (letters.find(cp)!=letters.end());
327     }
328 
is_sign(utf8::uint32_t cp) const329     bool is_sign(utf8::uint32_t cp) const
330     {
331       return (signs.find(cp)!=signs.end());
332     }
333 
has_common_letters(const language_info & other) const334     bool has_common_letters(const language_info& other) const
335     {
336       for(std::set<utf8::uint32_t>::const_iterator iter=letters.begin();iter!=letters.end();++iter)
337         {
338           if(other.is_letter(*iter))
339             return true;
340         }
341       return false;
342     }
343 
344     template<typename input_iterator>
count_letters_in_text(input_iterator first,input_iterator last) const345     std::size_t count_letters_in_text(input_iterator first,input_iterator last) const
346     {
347       std::size_t result=0;
348       for(input_iterator iter=first;iter!=last;++iter)
349         {
350           if(is_letter(*iter))
351             ++result;
352         }
353       return result;
354     }
355 
356     template<typename input_iterator>
are_all_letters(input_iterator first,input_iterator last) const357     bool are_all_letters(input_iterator first,input_iterator last) const
358     {
359       if(first==last)
360         return false;
361       for(input_iterator iter=first;iter!=last;++iter)
362         {
363           if(!is_letter(*iter))
364             return false;
365         }
366       return true;
367     }
368 
is_vowel_letter(utf8::uint32_t cp) const369     bool is_vowel_letter(utf8::uint32_t cp) const
370     {
371       return (vowel_letters.find(cp)!=vowel_letters.end());
372     }
373 
has_unicase_alphabet() const374     virtual bool has_unicase_alphabet() const
375     {
376       return false;
377     }
378 
get_alpha2_code() const379     const std::string& get_alpha2_code() const
380     {
381       return alpha2_code;
382     }
383 
get_alpha3_code() const384     const std::string& get_alpha3_code() const
385     {
386       return alpha3_code;
387     }
388 
389     #ifdef WIN32
390     virtual unsigned short get_id() const=0;
391     #endif
392 
get_country() const393     virtual std::string get_country() const
394     {
395       return std::string();
396     }
397 
supports_stress_marks() const398     virtual bool supports_stress_marks() const
399     {
400       return false;
401     }
402 
supports_pseudo_english() const403     virtual bool supports_pseudo_english() const
404     {
405       return false;
406     }
407 
408   protected:
409     virtual void do_register_settings(config& cfg,const std::string& prefix);
410 
411   private:
412     std::string alpha2_code,alpha3_code;
413     std::set<utf8::uint32_t> letters,vowel_letters,signs;
414     bool_property enabled;
415 
416   protected:
register_letter(utf8::uint32_t cp)417     void register_letter(utf8::uint32_t cp)
418     {
419       letters.insert(cp);
420     }
421 
register_letter_range(utf8::uint32_t cp,std::size_t n)422     void register_letter_range(utf8::uint32_t cp,std::size_t n)
423     {
424       for(std::size_t i=0;i<n;++i)
425         {
426           letters.insert(cp+i);
427         }
428     }
429 
register_vowel_letter(utf8::uint32_t cp)430     void register_vowel_letter(utf8::uint32_t cp)
431     {
432       vowel_letters.insert(cp);
433     }
434 
register_sign(utf8::uint32_t cp)435     void register_sign(utf8::uint32_t cp)
436     {
437       signs.insert(cp);
438     }
439 
440   public:
get_all_languages() const441     const language_list& get_all_languages() const
442     {
443       return *all_languages;
444     }
445 
446     std::vector<std::string> get_userdict_paths() const;
447 
448   private:
449     const language_list* all_languages;
450     std::string userdict_path;
451   };
452 
453   class language_list: public resource_list<language_info>
454   {
455   public:
456     language_list(const std::vector<std::string>& language_paths,const std::string& userdict_path,const event_logger& logger);
457 
458   private:
459     class creator
460     {
461     public:
creator()462       creator()
463       {
464       }
465 
~creator()466       virtual ~creator()
467       {
468       }
469 
470       virtual std::shared_ptr<language_info> create(const std::string& data_path,const std::string& userdict_path) const=0;
471 
472     private:
473       creator(const creator&);
474       creator& operator=(const creator&);
475     };
476 
477     template<class T>
478     class concrete_creator: public creator
479     {
480     public:
create(const std::string & data_path,const std::string & userdict_path) const481       std::shared_ptr<language_info> create(const std::string& data_path,const std::string& userdict_path) const
482       {
483         return std::shared_ptr<language_info>(new T(data_path,userdict_path));
484       }
485     };
486 
487     typedef std::pair<std::string,unsigned int> language_id;
488     typedef std::map<language_id,std::shared_ptr<creator> > Creators;
489 
490     template<class T>
register_language(const std::string & name,unsigned int format)491     void register_language(const std::string& name,unsigned int format)
492     {
493       creators[language_id(name,format)]=std::shared_ptr<creator>(new concrete_creator<T>);
494     }
495 
496     Creators creators;
497   };
498 
499   class language_search_criteria: public std::unary_function<const language_info&,bool>
500   {
501   public:
set_name(const std::string & name_)502     void set_name(const std::string& name_)
503     {
504       name=name_;
505     }
506 
clear_name()507     void clear_name()
508     {
509       name.clear();
510     }
511 
set_code(const std::string & code_)512     void set_code(const std::string& code_)
513     {
514       code=code_;
515     }
516 
clear_code()517     void clear_code()
518     {
519       code.clear();
520     }
521 
empty() const522     bool empty() const
523     {
524       return (name.empty()&&code.empty());
525     }
526 
527     bool operator()(const language_info& info) const;
528 
529   private:
530     std::string name,code;
531   };
532 
533   struct is_letter: std::unary_function<utf8::uint32_t,bool>
534   {
is_letterRHVoice::is_letter535     explicit is_letter(const language_info& lang_):
536       lang(&lang_)
537     {
538     }
539 
operator ()RHVoice::is_letter540     bool operator()(utf8::uint32_t cp) const
541     {
542       return lang->is_letter(cp);
543     }
544 
545   private:
546     const language_info* lang;
547   };
548 
549   struct is_vowel_letter: std::unary_function<utf8::uint32_t,bool>
550   {
is_vowel_letterRHVoice::is_vowel_letter551     explicit is_vowel_letter(const language_info& lang_):
552       lang(&lang_)
553     {
554     }
555 
operator ()RHVoice::is_vowel_letter556     bool operator()(utf8::uint32_t cp) const
557     {
558       return lang->is_vowel_letter(cp);
559     }
560 
561   private:
562     const language_info* lang;
563   };
564 }
565 #endif
566