001/** 002 * Portions Copyright 2001 Sun Microsystems, Inc. 003 * Portions Copyright 1999-2001 Language Technologies Institute, 004 * Carnegie Mellon University. 005 * All Rights Reserved. Use is subject to license terms. 006 * 007 * See the file "license.terms" for information on usage and 008 * redistribution of this file, and for a DISCLAIMER OF ALL 009 * WARRANTIES. 010 */ 011package com.sun.speech.freetts.en.us; 012 013import java.util.HashSet; 014import java.util.Set; 015import java.util.regex.Pattern; 016 017import com.sun.speech.freetts.FeatureProcessor; 018import com.sun.speech.freetts.Item; 019import com.sun.speech.freetts.PartOfSpeech; 020import com.sun.speech.freetts.PathExtractor; 021import com.sun.speech.freetts.PathExtractorImpl; 022import com.sun.speech.freetts.ProcessException; 023import com.sun.speech.freetts.Relation; 024import com.sun.speech.freetts.Voice; 025 026 027 028/** 029 * Provides the set of feature processors that are used by this 030 * language as part of the CART processing. 031 */ 032public class FeatureProcessors { 033 034 private final static PathExtractor FIRST_SYLLABLE_PATH = 035 new PathExtractorImpl( 036 "R:SylStructure.parent.R:Phrase.parent.daughter.R:SylStructure.daughter", 037 false); 038 039 private final static PathExtractor LAST_SYLLABLE_PATH = 040 new PathExtractorImpl( 041 "R:SylStructure.parent.R:Phrase.parent.daughtern.R:SylStructure.daughter", 042 false); 043 044 private final static PathExtractor LAST_LAST_SYLLABLE_PATH = 045 new PathExtractorImpl( 046 "R:SylStructure.parent.R:Phrase.parent.daughtern.R:SylStructure.daughtern", 047 false); 048 049 private final static PathExtractor SUB_PHRASE_PATH = 050 new PathExtractorImpl("R:SylStructure.parent.R:Phrase.parent.p", false); 051 052 private final static Pattern DOUBLE_PATTERN 053 = Pattern.compile(USEnglish.RX_DOUBLE); 054 055 private final static Pattern DIGITS_PATTERN 056 = Pattern.compile(USEnglish.RX_DIGITS); 057 058 private static Set months; 059 private static Set days; 060 061 // the set of month names 062 static { 063 months = new HashSet(); 064 months.add("jan"); 065 months.add("january"); 066 months.add("feb"); 067 months.add("february"); 068 months.add("mar"); 069 months.add("march"); 070 months.add("apr"); 071 months.add("april"); 072 months.add("may"); 073 months.add("jun"); 074 months.add("june"); 075 months.add("jul"); 076 months.add("july"); 077 months.add("aug"); 078 months.add("august"); 079 months.add("sep"); 080 months.add("september"); 081 months.add("oct"); 082 months.add("october"); 083 months.add("nov"); 084 months.add("november"); 085 months.add("dec"); 086 months.add("december"); 087 } 088 089 // the set of week neames 090 static { 091 days = new HashSet(); 092 days.add("sun"); 093 days.add("sunday"); 094 days.add("mon"); 095 days.add("monday"); 096 days.add("tue"); 097 days.add("tuesday"); 098 days.add("wed"); 099 days.add("wednesday"); 100 days.add("thu"); 101 days.add("thursday"); 102 days.add("fri"); 103 days.add("friday"); 104 days.add("sat"); 105 days.add("saturday"); 106 } 107 108 // no instances 109 private FeatureProcessors() {} 110 111 /** 112 * Returns a guess of the part-of-speech. 113 * 114 * This is a feature processor. A feature processor takes an item, 115 * performs some sort of processing on the item and returns an object. 116 */ 117 public static class Gpos implements FeatureProcessor { 118 PartOfSpeech pos; 119 /** 120 * Creates a GPOS with the given part-of-speech table 121 * 122 * @param pos part of speech determiner 123 */ 124 public Gpos(PartOfSpeech pos) { 125 this.pos = pos; 126 } 127 128 /** 129 * Performs some processing on the given item. 130 * 131 * @param item the item to process 132 * 133 * @return a guess at the part-of-speech for the item 134 * 135 * @throws ProcessException if an exception occurred during the 136 * processing 137 */ 138 public String process(Item item) throws ProcessException { 139 return pos.getPartOfSpeech(item.toString()); 140 } 141 } 142 143 144 /** 145 * Returns as an Integer the number of syllables in the given 146 * word. This is a feature processor. A feature processor takes an item, 147 * performs some sort of processing on the item and returns an object. 148 */ 149 public static class WordNumSyls implements FeatureProcessor { 150 151 /** 152 * Performs some processing on the given item. 153 * 154 * @param item the item to process 155 * 156 * @return the number of syllables in the given word 157 * 158 * @throws ProcessException if an exception occurred during the 159 * processing 160 */ 161 public String process(Item item) throws ProcessException { 162 int count = 0; 163 Item daughter = item.getItemAs( 164 Relation.SYLLABLE_STRUCTURE).getDaughter(); 165 while (daughter != null) { 166 count++; 167 daughter = daughter.getNext(); 168 } 169 return Integer.toString(rail(count)); 170 } 171 } 172 173 /** 174 * Counts the number of accented syllables since the last major break. 175 * This is a feature processor. A feature processor takes an item, 176 * performs some sort of processing on the item and returns an object. 177 */ 178 public static class AccentedSylIn implements FeatureProcessor { 179 180 /** 181 * Performs some processing on the given item. 182 * 183 * @param item the item to process 184 * 185 * @return the number of accented syllables since the last 186 * major break 187 * 188 * @throws ProcessException if an exception occurred during the 189 * processing 190 */ 191 public String process(Item item) throws ProcessException { 192 int count = 0; 193 Item ss = item.getItemAs(Relation.SYLLABLE); 194 Item firstSyllable = FIRST_SYLLABLE_PATH.findItem(item); 195 196 for (Item p = ss; p != null; p = p.getPrevious() ) { 197 if (isAccented(p)) { 198 count++; 199 } 200 if (p.equalsShared(firstSyllable)) { 201 break; 202 } 203 } 204 return Integer.toString(rail(count)); 205 } 206 } 207 208 209 /** 210 * Counts the number of stressed syllables since the last major break. 211 * This is a feature processor. A feature processor takes an item, 212 * performs some sort of processing on the item and returns an object. 213 */ 214 public static class StressedSylIn implements FeatureProcessor { 215 216 /** 217 * Performs some processing on the given item. 218 * 219 * @param item the item to process 220 * 221 * @return the number of stresses syllables since the last 222 * major break 223 * 224 * @throws ProcessException if an exception occurred during the 225 * processing 226 */ 227 public String process(Item item) throws ProcessException { 228 int count = 0; 229 Item ss = item.getItemAs(Relation.SYLLABLE); 230 Item firstSyllable = FIRST_SYLLABLE_PATH.findItem(item); 231 232 // this should include the first syllable, but 233 // flite 1.1 and festival don't. 234 235 for (Item p = ss.getPrevious(); 236 p != null && !p.equalsShared(firstSyllable); 237 p = p.getPrevious() ) { 238 if ("1".equals(p.getFeatures().getString("stress"))) { 239 count++; 240 } 241 } 242 return Integer.toString(rail(count)); 243 } 244 } 245 246 /** 247 * Counts the number of stressed syllables until the next major break. 248 * This is a feature processor. A feature processor takes an item, 249 * performs some sort of processing on the item and returns an object. 250 */ 251 public static class StressedSylOut implements FeatureProcessor { 252 253 /** 254 * Performs some processing on the given item. 255 * 256 * @param item the item to process 257 * 258 * @return the number of stressed syllables until the next major break 259 * 260 * @throws ProcessException if an exception occurred during the 261 * processing 262 */ 263 public String process(Item item) throws ProcessException { 264 int count = 0; 265 Item ss = item.getItemAs(Relation.SYLLABLE); 266 Item lastSyllable = LAST_SYLLABLE_PATH.findItem(item); 267 268 for (Item p = ss.getNext(); p != null; p = p.getNext() ) { 269 if ("1".equals(p.getFeatures().getString("stress"))) { 270 count++; 271 } 272 if (p.equalsShared(lastSyllable)) { 273 break; 274 } 275 } 276 return Integer.toString(rail(count)); 277 } 278 } 279 280 /** 281 * Returns the length of the string. (generally this is a digit 282 * string) 283 * This is a feature processor. A feature processor takes an item, 284 * performs some sort of processing on the item and returns an object. 285 */ 286 public static class NumDigits implements FeatureProcessor { 287 288 /** 289 * Performs some processing on the given item. 290 * 291 * @param item the item to process 292 * 293 * @return the length of the string 294 * 295 * @throws ProcessException if an exception occurred during the 296 * processing 297 */ 298 public String process(Item item) throws ProcessException { 299 String name = item.getFeatures().getString("name"); 300 return Integer.toString(rail(name.length())); 301 } 302 } 303 304 /** 305 * Returns true ("1") if the given item is a number between 0 and 306 * 32 exclusive, otherwise, returns "0". 307 * string) 308 * This is a feature processor. A feature processor takes an item, 309 * performs some sort of processing on the item and returns an object. 310 */ 311 public static class MonthRange implements FeatureProcessor { 312 313 /** 314 * Performs some processing on the given item. 315 * 316 * @param item the item to process 317 * 318 * @return returns "1" if the given item is a number between 0 319 * and 32 (exclusive) otherwise returns "0" 320 * 321 * @throws ProcessException if an exception occurred during the 322 * processing 323 */ 324 public String process(Item item) throws ProcessException { 325 int v = Integer.parseInt(item.getFeatures().getString("name")); 326 if ((v > 0) && (v < 32)) { 327 return "1"; 328 } else { 329 return "0"; 330 } 331 } 332 } 333 334 /** 335 * Attempts to guess the part of speech. 336 * This is a feature processor. A feature processor takes an item, 337 * performs some sort of processing on the item and returns an object. 338 */ 339 public static class TokenPosGuess implements FeatureProcessor { 340 /** 341 * Performs some processing on the given item. 342 * 343 * @param item the item to process 344 * 345 * @return a guess at the part of speech 346 * 347 * @throws ProcessException if an exception occurred during the 348 * processing 349 */ 350 public String process(Item item) throws ProcessException { 351 String name = item.getFeatures().getString("name"); 352 String dc = name.toLowerCase(); 353 if (DIGITS_PATTERN.matcher(dc).matches()) { 354 return "numeric"; 355 } else if (DOUBLE_PATTERN.matcher(dc).matches()) { 356 return "number"; 357 } else if (months.contains(dc)) { 358 return "month"; 359 } else if (days.contains(dc)) { 360 return "day"; 361 } else if (dc.equals("a")) { 362 return "a"; 363 } else if (dc.equals("flight")) { 364 return "flight"; 365 } else if (dc.equals("to")) { 366 return "to"; 367 } else { 368 return "_other_"; 369 } 370 } 371 } 372 373 /** 374 * Checks to see if the given syllable is accented. 375 * This is a feature processor. A feature processor takes an item, 376 * performs some sort of processing on the item and returns an object. 377 */ 378 public static class Accented implements FeatureProcessor { 379 380 /** 381 * Performs some processing on the given item. 382 * @param item the item to process 383 * 384 * @return "1" if the syllable is accented; otherwise "0" 385 * 386 * @throws ProcessException if an exception occurred during the 387 * processing 388 */ 389 public String process(Item item) throws ProcessException { 390 if (isAccented(item)) { 391 return "1"; 392 } else { 393 return "0"; 394 } 395 } 396 } 397 398 /** 399 * Find the last accented syllable 400 * This is a feature processor. A feature processor takes an item, 401 * performs some sort of processing on the item and returns an object. 402 */ 403 public static class LastAccent implements FeatureProcessor { 404 405 /** 406 * Performs some processing on the given item. 407 * 408 * @param item the item to process 409 * 410 * @return the count of the last accented syllable 411 * 412 * @throws ProcessException if an exception occurred during the 413 * processing 414 */ 415 public String process(Item item) throws ProcessException { 416 int count = 0; 417 418 for (Item p = item.getItemAs(Relation.SYLLABLE); 419 p != null; p = p.getPrevious(), count++) { 420 if (isAccented(p)) { 421 break; 422 } 423 } 424 return Integer.toString(rail(count)); 425 } 426 } 427 428 /** 429 * Finds the position of the phoneme in the syllable 430 * This is a feature processor. A feature processor takes an item, 431 * performs some sort of processing on the item and returns an object. 432 */ 433 public static class PosInSyl implements FeatureProcessor { 434 435 /** 436 * Performs some processing on the given item. 437 * 438 * @param item the item to process 439 * 440 * @return the position of the phoneme in the syllable 441 * 442 * @throws ProcessException if an exception occurred during the 443 * processing 444 */ 445 public String process(Item item) throws ProcessException { 446 int count = -1; 447 448 for (Item p = item.getItemAs(Relation.SYLLABLE_STRUCTURE); 449 p != null; p = p.getPrevious() ) { 450 count++; 451 } 452 return Integer.toString(rail(count)); 453 } 454 } 455 456 /** 457 * Classifies the the syllable as single, initial, mid or final. 458 * This is a feature processor. A feature processor takes an item, 459 * performs some sort of processing on the item and returns an object. 460 */ 461 public static class PositionType implements FeatureProcessor { 462 463 /** 464 * Performs some processing on the given item. 465 * 466 * @param item the item to process 467 * 468 * @return classifies the syllable as "single", "final", 469 * "initial" or "mid" 470 * 471 * @throws ProcessException if an exception occurred during the 472 * processing 473 */ 474 public String process(Item item) throws ProcessException { 475 String type; 476 477 Item s = item.getItemAs(Relation.SYLLABLE_STRUCTURE); 478 if (s == null) { 479 type = "single"; 480 } else if (s.getNext() == null) { 481 if (s.getPrevious() == null) { 482 type = "single"; 483 } else { 484 type = "final"; 485 } 486 } else if (s.getPrevious() == null) { 487 type = "initial"; 488 } else { 489 type = "mid"; 490 } 491 return type; 492 } 493 } 494 495 496 /** 497 * Counts the number of stressed syllables since the last major break. 498 * This is a feature processor. A feature processor takes an item, 499 * performs some sort of processing on the item and returns an object. 500 */ 501 public static class SylIn implements FeatureProcessor { 502 503 /** 504 * Performs some processing on the given item. 505 * 506 * @param item the item to process 507 * 508 * @return the number of stressed syllables since the last 509 * major break 510 * 511 * @throws ProcessException if an exception occurred during the 512 * processing 513 */ 514 public String process(Item item) throws ProcessException { 515 int count = 0; 516 Item ss = item.getItemAs(Relation.SYLLABLE); 517 Item firstSyllable = FIRST_SYLLABLE_PATH.findItem(item); 518 519 for (Item p = ss; p != null; p = p.getPrevious(), count++ ) { 520 if (p.equalsShared(firstSyllable)) { 521 break; 522 } 523 } 524 return Integer.toString(rail(count)); 525 } 526 } 527 528 /** 529 * Counts the number of stressed syllables since the last major break. 530 * This is a feature processor. A feature processor takes an item, 531 * performs some sort of processing on the item and returns an object. 532 */ 533 public static class SylOut implements FeatureProcessor { 534 535 /** 536 * Performs some processing on the given item. 537 * 538 * @param item the item to process 539 * 540 * @return the number of stressed syllables since the last 541 * major break 542 * 543 * @throws ProcessException if an exception occurred during the 544 * processing 545 */ 546 public String process(Item item) throws ProcessException { 547 int count = 0; 548 Item ss = item.getItemAs(Relation.SYLLABLE); 549 Item firstSyllable = LAST_LAST_SYLLABLE_PATH.findItem(item); 550 551 for (Item p = ss; p != null; p = p.getNext() ) { 552 if (p.equalsShared(firstSyllable)) { 553 break; 554 } 555 count++; 556 } 557 return Integer.toString(rail(count)); 558 } 559 } 560 561 562 /** 563 * Determines the break level after this syllable 564 * This is a feature processor. A feature processor takes an item, 565 * performs some sort of processing on the item and returns an object. 566 */ 567 public static class SylBreak implements FeatureProcessor { 568 569 /** 570 * Performs some processing on the given item. 571 * 572 * @param syl the item to process 573 * 574 * @return the break level after this syllable 575 * 576 * @throws ProcessException if an exception occurred during the 577 * processing 578 */ 579 public String process(Item syl) throws ProcessException { 580 Item ss = syl.getItemAs(Relation.SYLLABLE_STRUCTURE); 581 if (ss == null) { 582 return "1"; 583 } else if (ss.getNext() != null) { 584 return "0"; 585 } else if (ss.getParent() == null) { 586 return "1"; 587 } else { 588 return wordBreak(ss.getParent()); 589 } 590 } 591 } 592 593 594 595 /** 596 * Determines the word break. 597 * This is a feature processor. A feature processor takes an item, 598 * performs some sort of processing on the item and returns an object. 599 */ 600 public static class WordBreak implements FeatureProcessor { 601 602 /** 603 * Performs some processing on the given item. 604 * 605 * @param word the item to process 606 * 607 * @return the break level for this word 608 * 609 * @throws ProcessException if an exception occurred during the 610 * processing 611 */ 612 public String process(Item word) throws ProcessException { 613 return wordBreak(word); 614 } 615 } 616 617 /** 618 * Determines the word punctuation. 619 * This is a feature processor. A feature processor takes an item, 620 * performs some sort of processing on the item and returns an object. 621 */ 622 public static class WordPunc implements FeatureProcessor { 623 624 /** 625 * Performs some processing on the given item. 626 * 627 * @param word the item to process 628 * 629 * @return the punctuation for this word 630 * 631 * @throws ProcessException if an exception occurred during the 632 * processing 633 */ 634 public String process(Item word) throws ProcessException { 635 return wordPunc(word); 636 } 637 } 638 639 /** 640 * Return consonant cplace 641 * l-labial a-alveolar p-palatal b-labio_dental d-dental v-velar 642 * 643 * This is a feature processor. A feature processor takes an item, 644 * performs some sort of processing on the item and returns an object. 645 */ 646 public static class PH_CPlace implements FeatureProcessor { 647 648 /** 649 * Performs some processing on the given item. 650 * 651 * @param item the item to process 652 * 653 * @return consonant cplace 654 * 655 * @throws ProcessException if an exception occurred during the 656 * processing 657 */ 658 public String process(Item item) throws ProcessException { 659 return getPhoneFeature(item, "cplace"); 660 } 661 } 662 663 /** 664 * Return consonant type 665 * s-stop f-fricative a-affricative n-nasal * l-liquid 666 * 667 * This is a feature processor. A feature processor takes an item, 668 * performs some sort of processing on the item and returns an object. 669 */ 670 public static class PH_CType implements FeatureProcessor { 671 672 /** 673 * Performs some processing on the given item. 674 * 675 * @param item the item to process 676 * 677 * @return consonant type 678 * 679 * @throws ProcessException if an exception occurred during the 680 * processing 681 */ 682 public String process(Item item) throws ProcessException { 683 return getPhoneFeature(item, "ctype"); 684 } 685 } 686 687 /** 688 * Return consonant voicing 689 * +=on -=off 690 * 691 * This is a feature processor. A feature processor takes an item, 692 * performs some sort of processing on the item and returns an object. 693 */ 694 public static class PH_CVox implements FeatureProcessor { 695 696 /** 697 * Performs some processing on the given item. 698 * 699 * @param item the item to process 700 * 701 * @return consonant voicing 702 * 703 * @throws ProcessException if an exception occurred during the 704 * processing 705 */ 706 public String process(Item item) throws ProcessException { 707 return getPhoneFeature(item, "cvox"); 708 } 709 } 710 711 /** 712 * Return vowel or consonant 713 * +=on -=off 714 * 715 * This is a feature processor. A feature processor takes an item, 716 * performs some sort of processing on the item and returns an object. 717 */ 718 public static class PH_VC implements FeatureProcessor { 719 720 /** 721 * Performs some processing on the given item. 722 * 723 * @param item the item to process 724 * 725 * @return vowel or consonant 726 * 727 * @throws ProcessException if an exception occurred during the 728 * processing 729 */ 730 public String process(Item item) throws ProcessException { 731 return getPhoneFeature(item, "vc"); 732 } 733 } 734 735 /** 736 * Return vowel frontness 737 * 1-front 2-mid 3-back 738 * 739 * This is a feature processor. A feature processor takes an item, 740 * performs some sort of processing on the item and returns an object. 741 */ 742 public static class PH_VFront implements FeatureProcessor { 743 744 /** 745 * Performs some processing on the given item. 746 * 747 * @param item the item to process 748 * 749 * @return vowel frontness 750 * 751 * @throws ProcessException if an exception occurred during the 752 * processing 753 */ 754 public String process(Item item) throws ProcessException { 755 return getPhoneFeature(item, "vfront"); 756 } 757 } 758 759 /** 760 * Return vowel height 761 * 1-high 2-mid 3-low 762 * 763 * This is a feature processor. A feature processor takes an item, 764 * performs some sort of processing on the item and returns an object. 765 */ 766 public static class PH_VHeight implements FeatureProcessor { 767 768 /** 769 * Performs some processing on the given item. 770 * 771 * @param item the item to process 772 * 773 * @return vowel height 774 * 775 * @throws ProcessException if an exception occurred during the 776 * processing 777 */ 778 public String process(Item item) throws ProcessException { 779 return getPhoneFeature(item, "vheight"); 780 } 781 } 782 783 784 /** 785 * Return vowel length 786 * s-short l-long d-dipthong a-schwa 787 * 788 * This is a feature processor. A feature processor takes an item, 789 * performs some sort of processing on the item and returns an object. 790 */ 791 public static class PH_VLength implements FeatureProcessor { 792 793 /** 794 * Performs some processing on the given item. 795 * 796 * @param item the item to process 797 * 798 * @return vowel length 799 * 800 * @throws ProcessException if an exception occurred during the 801 * processing 802 */ 803 public String process(Item item) throws ProcessException { 804 return getPhoneFeature(item, "vlng"); 805 } 806 } 807 808 809 810 811 /** 812 * Return vowel rnd (lip rounding) 813 * lip rounding +=on -=off 814 * 815 * This is a feature processor. A feature processor takes an item, 816 * performs some sort of processing on the item and returns an object. 817 */ 818 public static class PH_VRnd implements FeatureProcessor { 819 820 /** 821 * Performs some processing on the given item. 822 * 823 * @param item the item to process 824 * 825 * @return volwel rnd 826 * 827 * @throws ProcessException if an exception occurred during the 828 * processing 829 */ 830 public String process(Item item) throws ProcessException { 831 return getPhoneFeature(item, "vrnd"); 832 } 833 } 834 835 /** 836 * Determines the onset size of this syllable 837 * This is a feature processor. A feature processor takes an item, 838 * performs some sort of processing on the item and returns an object. 839 */ 840 public static class SylOnsetSize implements FeatureProcessor { 841 842 /** 843 * Performs some processing on the given item. 844 * 845 * @param syl the item to process 846 * 847 * @return onset size of this syllable 848 * 849 * @throws ProcessException if an exception occurred during the 850 * processing 851 */ 852 public String process(Item syl) throws ProcessException { 853 int count = 0; 854 Item daughter = syl.getItemAs( 855 Relation.SYLLABLE_STRUCTURE).getDaughter(); 856 while (daughter != null) { 857 if ("+".equals(getPhoneFeature(daughter, "vc"))) { 858 break; 859 } 860 count++; 861 daughter = daughter.getNext(); 862 } 863 return Integer.toString(rail(count)); 864 } 865 } 866 867 868 /** 869 * Determines the coda size 870 * This is a feature processor. A feature processor takes an item, 871 * performs some sort of processing on the item and returns an object. 872 */ 873 public static class SylCodaSize implements FeatureProcessor { 874 875 /** 876 * Performs some processing on the given item. 877 * 878 * @param syl the item to process 879 * 880 * @return coda size 881 * 882 * @throws ProcessException if an exception occurred during the 883 * processing 884 */ 885 public String process(Item syl) throws ProcessException { 886 int count = 0; 887 Item daughter = syl.getItemAs( 888 Relation.SYLLABLE_STRUCTURE).getLastDaughter(); 889 890 while (daughter != null) { 891 if ("+".equals(getPhoneFeature(daughter, "vc"))) { 892 break; 893 } 894 895 daughter = daughter.getPrevious(); 896 count++; 897 } 898 return Integer.toString(rail(count)); 899 } 900 } 901 902 903 /** 904 * Checks for fricative 905 * This is a feature processor. A feature processor takes an item, 906 * performs some sort of processing on the item and returns an object. 907 */ 908 public static class SegCodaFric implements FeatureProcessor { 909 910 /** 911 * Performs some processing on the given item. 912 * 913 * @param seg the item to process 914 * 915 * @return "1" if fricative; else "0" 916 * 917 * @throws ProcessException if an exception occurred during the 918 * processing 919 */ 920 public String process(Item seg) throws ProcessException { 921 return segCodaCtype(seg, "f"); 922 } 923 } 924 925 /** 926 * Checks for fricative 927 * This is a feature processor. A feature processor takes an item, 928 * performs some sort of processing on the item and returns an object. 929 */ 930 public static class SegOnsetFric implements FeatureProcessor { 931 932 /** 933 * Performs some processing on the given item. 934 * 935 * @param seg the item to process 936 * 937 * @return "1" if fricative; else "0" 938 * 939 * @throws ProcessException if an exception occurred during the 940 * processing 941 */ 942 public String process(Item seg) throws ProcessException { 943 return segOnsetCtype(seg, "f"); 944 } 945 } 946 947 948 949 /** 950 * Checks for coda stop 951 * This is a feature processor. A feature processor takes an item, 952 * performs some sort of processing on the item and returns an object. 953 */ 954 public static class SegCodaStop implements FeatureProcessor { 955 956 /** 957 * Performs some processing on the given item. 958 * 959 * @param seg the item to process 960 * 961 * @return if coda stop "1"; otherwise "0" 962 * 963 * @throws ProcessException if an exception occurred during the 964 * processing 965 */ 966 public String process(Item seg) throws ProcessException { 967 return segCodaCtype(seg, "s"); 968 } 969 } 970 971 /** 972 * Checks for onset stop 973 * This is a feature processor. A feature processor takes an item, 974 * performs some sort of processing on the item and returns an object. 975 */ 976 public static class SegOnsetStop implements FeatureProcessor { 977 978 /** 979 * Performs some processing on the given item. 980 * 981 * @param seg the item to process 982 * 983 * @return if Onset Stop "1"; otherwise "0" 984 * 985 * @throws ProcessException if an exception occurred during the 986 * processing 987 */ 988 public String process(Item seg) throws ProcessException { 989 return segOnsetCtype(seg, "s"); 990 } 991 } 992 993 /** 994 * Checks for coda nasal 995 * This is a feature processor. A feature processor takes an item, 996 * performs some sort of processing on the item and returns an object. 997 */ 998 public static class SegCodaNasal implements FeatureProcessor { 999 1000 /** 1001 * Performs some processing on the given item. 1002 * 1003 * @param seg the item to process 1004 * 1005 * @return if coda stop "1"; otherwise "0" 1006 * 1007 * @throws ProcessException if an exception occurred during the 1008 * processing 1009 */ 1010 public String process(Item seg) throws ProcessException { 1011 return segCodaCtype(seg, "n"); 1012 } 1013 } 1014 1015 /** 1016 * Checks for onset nasal 1017 * This is a feature processor. A feature processor takes an item, 1018 * performs some sort of processing on the item and returns an object. 1019 */ 1020 public static class SegOnsetNasal implements FeatureProcessor { 1021 1022 /** 1023 * Performs some processing on the given item. 1024 * 1025 * @param seg the item to process 1026 * 1027 * @return if Onset Stop "1"; otherwise "0" 1028 * 1029 * @throws ProcessException if an exception occurred during the 1030 * processing 1031 */ 1032 public String process(Item seg) throws ProcessException { 1033 return segOnsetCtype(seg, "n"); 1034 } 1035 } 1036 1037 /** 1038 * Checks for coda glide 1039 * This is a feature processor. A feature processor takes an item, 1040 * performs some sort of processing on the item and returns an object. 1041 */ 1042 public static class SegCodaGlide implements FeatureProcessor { 1043 1044 /** 1045 * Performs some processing on the given item. 1046 * 1047 * @param seg the item to process 1048 * 1049 * @return if coda stop "1"; otherwise "0" 1050 * 1051 * @throws ProcessException if an exception occurred during the 1052 * processing 1053 */ 1054 public String process(Item seg) throws ProcessException { 1055 if (segCodaCtype(seg, "r").equals("0")) { 1056 return segCodaCtype(seg, "l"); 1057 } 1058 return "1"; 1059 } 1060 } 1061 1062 /** 1063 * Checks for onset glide 1064 * This is a feature processor. A feature processor takes an item, 1065 * performs some sort of processing on the item and returns an object. 1066 */ 1067 public static class SegOnsetGlide implements FeatureProcessor { 1068 1069 /** 1070 * Performs some processing on the given item. 1071 * 1072 * @param seg the item to process 1073 * 1074 * @return if coda stop "1"; otherwise "0" 1075 * 1076 * @throws ProcessException if an exception occurred during the 1077 * processing 1078 */ 1079 public String process(Item seg) throws ProcessException { 1080 if (segOnsetCtype(seg, "r").equals("0")) { 1081 return segOnsetCtype(seg, "l"); 1082 } 1083 return "1"; 1084 } 1085 } 1086 1087 1088 /** 1089 * Checks for onset coda 1090 * This is a feature processor. A feature processor takes an item, 1091 * performs some sort of processing on the item and returns an object. 1092 */ 1093 public static class SegOnsetCoda implements FeatureProcessor { 1094 1095 /** 1096 * Performs some processing on the given item. 1097 * 1098 * @param seg the item to process 1099 * 1100 * @return if onset coda "1"; otherwise "0" 1101 * 1102 * @throws ProcessException if an exception occurred during the 1103 * processing 1104 */ 1105 public String process(Item seg) throws ProcessException { 1106 Item s = seg.getItemAs(Relation.SYLLABLE_STRUCTURE); 1107 if (s == null) { 1108 return "coda"; 1109 } 1110 1111 s = s.getNext(); 1112 while (s != null) { 1113 if ("+".equals(getPhoneFeature(s, "vc"))) { 1114 return "onset"; 1115 } 1116 1117 s = s.getNext(); 1118 } 1119 1120 return "coda"; 1121 } 1122 } 1123 1124 /** 1125 * Counts the number of phrases before this one. 1126 * This is a feature processor. A feature processor takes an item, 1127 * performs some sort of processing on the item and returns an object. 1128 */ 1129 public static class SubPhrases implements FeatureProcessor { 1130 1131 /** 1132 * Performs some processing on the given item. 1133 * 1134 * @param item the item to process 1135 * 1136 * @return the number of phrases before this one 1137 * 1138 * @throws ProcessException if an exception occurred during the 1139 * processing 1140 */ 1141 public String process(Item item) throws ProcessException { 1142 int count = 0; 1143 Item inPhrase = SUB_PHRASE_PATH.findItem(item); 1144 1145 for (Item p = inPhrase; p != null; p = p.getPrevious() ) { 1146 count++; 1147 } 1148 return Integer.toString(rail(count)); 1149 } 1150 } 1151 1152 /** 1153 * Returns the duration of the given segment 1154 * This is a feature processor. A feature processor takes an item, 1155 * performs some sort of processing on the item and returns an object. 1156 */ 1157 public static class SegmentDuration implements FeatureProcessor { 1158 1159 /** 1160 * Performs some processing on the given item. 1161 * 1162 * @param seg the item to process 1163 * 1164 * @return the duration of the segment as a string. 1165 * 1166 * @throws ProcessException if an exception occurred during the 1167 * processing 1168 */ 1169 public String process(Item seg) throws ProcessException { 1170 if (seg == null) { 1171 return "0"; 1172 } else if (seg.getPrevious() == null) { 1173 return seg.getFeatures().getObject("end").toString(); 1174 } else { 1175 return Float.toString( 1176 seg.getFeatures().getFloat("end") - 1177 seg.getPrevious().getFeatures().getFloat("end") 1178 ); 1179 } 1180 } 1181 } 1182 1183 /** 1184 * Gets the phoneset feature with the given name 1185 * 1186 * @param item item the phoneme of interest 1187 * @param featureName the feature of interest 1188 * 1189 * @return the phone feature for the item 1190 * 1191 */ 1192 1193 public static String getPhoneFeature(Item item, String featureName) { 1194 Voice voice = item.getUtterance().getVoice(); 1195 String feature = voice.getPhoneFeature(item.toString(), featureName); 1196 return feature; 1197 } 1198 1199 /** 1200 * Classifies the type of word break 1201 * 1202 * @param item the item to process 1203 * 1204 * @return "4" for a big break, "3" for a break; otherwise "1" 1205 * 1206 * @throws ProcessException if an exception occurred during the 1207 * processing 1208 */ 1209 public static String wordBreak(Item item) throws ProcessException { 1210 Item ww = item.getItemAs(Relation.PHRASE); 1211 if (ww == null || ww.getNext() != null) { 1212 return "1"; 1213 } else { 1214 String pname = ww.getParent().toString(); 1215 if (pname.equals("BB")) { 1216 return "4"; 1217 } else if (pname.equals("B")) { 1218 return "3"; 1219 } else { 1220 return "1"; 1221 } 1222 } 1223 } 1224 1225 /** 1226 * Gets the punctuation associated with the word 1227 * 1228 * @param item the word to process 1229 * 1230 * @return the punctuation associated with the word 1231 * 1232 * @throws ProcessException if an exception occurred during the 1233 * processing 1234 */ 1235 public static String wordPunc(Item item) throws ProcessException { 1236 Item ww = item.getItemAs(Relation.TOKEN); 1237 if (ww != null && ww.getNext() != null) { 1238 return ""; 1239 } else { 1240 if (ww != null && ww.getParent() != null) { 1241 return ww.getParent().getFeatures().getString("punc"); 1242 } else { 1243 return ""; 1244 } 1245 } 1246 } 1247 1248 /** 1249 * Tests the coda ctype of the given segment. 1250 * 1251 * @param seg the segment to test 1252 * @param ctype the ctype to check for 1253 * 1254 * @return "1" on match "0" on no match 1255 */ 1256 private static String segCodaCtype(Item seg, String ctype) { 1257 Item daughter 1258 = seg.getItemAs( 1259 Relation.SYLLABLE_STRUCTURE).getParent().getLastDaughter(); 1260 1261 while (daughter != null) { 1262 if ("+".equals(getPhoneFeature(daughter, "vc"))) { 1263 return "0"; 1264 } 1265 if (ctype.equals(getPhoneFeature(daughter, "ctype"))) { 1266 return "1"; 1267 } 1268 1269 daughter = daughter.getPrevious(); 1270 } 1271 return "0"; 1272 } 1273 1274 /** 1275 * Tests the onset ctype of the given segment. 1276 * 1277 * @param seg the segment to test to process 1278 * @param ctype the ctype to check for 1279 * 1280 * @return if Onset Stop "1"; otherwise "0" 1281 * 1282 */ 1283 private static String segOnsetCtype(Item seg, String ctype) { 1284 Item daughter = seg.getItemAs( 1285 Relation.SYLLABLE_STRUCTURE).getParent().getDaughter(); 1286 1287 while (daughter != null) { 1288 if ("+".equals(getPhoneFeature(daughter, "vc"))) { 1289 return "0"; 1290 } 1291 if (ctype.equals(getPhoneFeature(daughter, "ctype"))) { 1292 return "1"; 1293 } 1294 1295 daughter = daughter.getNext(); 1296 } 1297 return "0"; 1298 } 1299 1300 /** 1301 * Determines if the given item is accented 1302 * 1303 * @param item the item of interest 1304 * 1305 * @return <code>true</code> if the item is accented, otherwise 1306 * <code>false</code> 1307 */ 1308 private static boolean isAccented(Item item) { 1309 return (item.getFeatures().isPresent("accent") || 1310 item.getFeatures().isPresent("endtone")); 1311 } 1312 1313 /** 1314 * Rails an int. flite never returns an int more than 19 from 1315 * a feature processor, we duplicate that behavior 1316 * here so that our tests will match. 1317 * 1318 * @param val the value to rail 1319 * 1320 * @return val clipped to be betweein 0 and 19 1321 */ 1322 private static int rail(int val) { 1323 return val > 19 ? 19 : val; 1324 } 1325}