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