summaryrefslogtreecommitdiff
path: root/lib/voices/finnish/hy_fi_mv_diphone/festvox/finnish_lts.scm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/voices/finnish/hy_fi_mv_diphone/festvox/finnish_lts.scm')
-rw-r--r--lib/voices/finnish/hy_fi_mv_diphone/festvox/finnish_lts.scm829
1 files changed, 829 insertions, 0 deletions
diff --git a/lib/voices/finnish/hy_fi_mv_diphone/festvox/finnish_lts.scm b/lib/voices/finnish/hy_fi_mv_diphone/festvox/finnish_lts.scm
new file mode 100644
index 0000000..a9e88b9
--- /dev/null
+++ b/lib/voices/finnish/hy_fi_mv_diphone/festvox/finnish_lts.scm
@@ -0,0 +1,829 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; ;;
+;;; Department of General Linguistics / Suopuhe project ;;
+;;; University of Helsinki, FI ;;
+;;; Copyright (c) 2000-2003 ;;
+;;; All Rights Reserved. ;;
+;;; ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; ;;;
+;;; ;;;
+;;; Author: Nicholas Volk ;;;
+;;; e-mail: nvolk@ling.helsinki.fi ;;;
+;;; address: Department of General Linguistics ;;;
+;;; PL 9 (Siltavuorenpenger 20A) ;;;
+;;; 00014 University of Helsinki ;;;
+;;; FINLAND ;;;
+;;; ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
+;;; Finnish LTS-rules, which fake the lexicon
+;;; (somewhat similar to the Festival Spanish)
+;;;
+;;; This file contains the LTS rules for Finnish.
+;;; The LTS rules also syllabify and mark the stressed syllables
+
+; This program is distributed under Gnu Lesser General Public License (cf. the
+; file LICENSE in distribution).
+
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU Lesser General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU Lesser General Public License for more details.
+
+(require 'finnish_lex) ;; POS (content vs. function) information is in lex
+
+
+(define (finnish_lts word)
+ "(finnish_lts WORD)
+Creates the lexical entry for the given WORD."
+ (if hy_debug (format stderr "Creating the lexical entry for %s.\n" word))
+
+ ;; in suopuhe-mode:
+ ;; reverse the stacks, if that has not been done yet...
+ (if (and suopuhe
+ (not pos_reversed))
+ (begin
+ (set! suopuhe_accent_stack (reverse suopuhe_accent_stack))
+ (set! suopuhe_pos_stack (reverse suopuhe_pos_stack))
+ (set! pos_reversed t)))
+
+
+ ;; check the string
+ ;; if there are unknown characters, replace them with "tuntematonmerkki"
+ ;; ("unknowncharacter")
+ (set! word
+ (let ((new "")
+ (state 0) ;; 0: initial state 1: prev is ordinary 2: unknown prev
+ char)
+ (while (> (string-length word) 0)
+ (begin
+ (set! char (substring word 0 1))
+ (set! word (substring word 1 (- (string-length word) 1)))
+ (cond
+ ;; ad hoc: LTS can't replace right bracket \] "]"
+ ((string-equal "\]" char)
+ (set! new
+ (string-append
+ (if new new "")
+ (if (> state 0) "-" "")
+ "oikeahakasulku"))
+ (set! state 2))
+ ((string-matches char "^[ a-zA-Z0-9\"\'\`\$%&\(\)\*\+\-~_\^/\\\?\}\{\@\.:!]$" )
+ (set! new
+ (string-append
+ (if new new "")
+ (if (= state 2) "-" "")
+ char))
+ (set! state 1))
+ (t
+ (set! new
+ (string-append
+ (if new new "")
+ (if (> state 0) "-" "")
+ "tuntematonmerkki"))
+ (set! state 2)))))
+ new))
+
+
+ (cond
+ ;; suopuhe mode gets hopefully the pos from a stack
+ (suopuhe
+ (let ((pos (pop_pos))
+ (acc (pop_accent)))
+ (set! pos (if (string-equal "unknown" pos)
+ (cond
+ ((word_list_entry? word finnish_guess_coord)
+ "COORD")
+ ((word_list_entry? word finnish_guess_cop)
+ "COP")
+ ((word_list_entry? word finnish_guess_pron)
+ "PRON")
+ ((word_list_entry? word finnish_guess_pos)
+ "function")
+ (t
+ "content"))))
+ ;; anyway... if word is defined as accentless we change
+ ;; the POS in the lexical entry to FUNCTION overriding the
+ ;; defined POS!
+ ;; accented words get POS CONTENT on the same basis...
+ (if (string-equal acc "no")
+ (set! pos "function")
+ (if (string-equal acc "yes")
+ (set! pos "content")))
+
+ (let ((x (list word (pop_pos) (compound_stress word))))
+ x)))
+ ;; non-suopuhe mode
+ ((word_list_entry? word finnish_guess_coord)
+ (list word "COORD" (compound_stress word)))
+ ((word_list_entry? word finnish_guess_cop)
+ (list word "COP" (compound_stress word)))
+ ((word_list_entry? word finnish_guess_pron)
+ (list word "PRON" (compound_stress word)))
+ ((word_list_entry? word finnish_guess_pos)
+ (list word "function" (compound_stress word)))
+ (t
+ (list word "content" (compound_stress word)))))
+
+(define (finnish_token_to_words token name)
+ "(finnish_token_to_words token name)
+A few simple ad hoc solutions for the most common simple T2W-problems.
+It was much nicer to use an external Perl text normalizer than scheme."
+ (cond
+ ;; NAN: begins with a 0, thsus sequence of digit
+ ((string-matches name "^0[0-9]*$")
+ (symbolexplode name))
+ ;; hundereds of millions are read as digits
+ ((string-matches name "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]+$")
+ (symbolexplode name))
+ ;; ordinary number (no inflections in scheme, use perl)
+ ((string-matches name "^[1-9][0-9]*$")
+ (list (finnish_number name)))
+ ;; Too many initial consonants
+ ((string-matches name "^[BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz][BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz][BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz][BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz].*$")
+ (symbolexplode name))
+ ;; separate consonant sequence from each other : "KGB" => "K G B"
+ ((string-matches name "^\\(.*\-\\)?[BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz]+\\(\-.*\\)?$")
+ (symbolexplode name))
+ ;; do nothing
+ (t
+ (list name))))
+
+(define (finnish_number int)
+ "(finnish_number INT)
+Converts the INT into a corresponding string.
+Very simple. Does not handle cases."
+ (remove_head_and_tail_spaces (make_number int)))
+
+(define (remove_head_and_tail_spaces text)
+ "(remove_head_and_tail_spaces string)
+Removes unspoken space sequences from the beginning and end of a give string."
+ (if (not (string-equal (typeof text) "string"))
+ (begin
+ (set! text "The input was not a string!")))
+
+ ;; remove the initial whitespaces
+ (while (and (> (string-length text) 0)
+ (string-matches (substring text 0 1) "^[ \t\n\015]$"))
+ ;; \015 = CTRL-M = carriage return
+ (set! text (substring text 1 (- (string-length text) 1))))
+ ;; remove the final whitespaces
+ (while (and (> (string-length text) 0)
+ (string-matches
+ (substring text (- (string-length text) 1) 1)
+ "^[ \t\n\015]$"))
+ (set! text (substring text 0 (- (string-length text) 1))))
+ text)
+
+
+(define (make_number int)
+ "(make_number INT)
+Splits numbers into 3-letter chunks, which are converted into a number.
+Also adds an appropriate quantifier (like thousands) to each triplet,
+thus producing any int between 1 - 999999999."
+ (let (head)
+ (cond
+ ((> (string-length int) 6)
+ (set! head (substring int 0 (- (string-length int) 6)))
+ (set! int (substring int (string-length head) 6))
+ (if (string-equal head "1")
+ (string-append
+ "miljoona "
+ (make_number int))
+ (string-append
+ (make_number2 head)
+ "miljoonaa "
+ (make_number int))))
+ ((> (string-length int) 3)
+ (set! head (substring int 0 (- (string-length int) 3)))
+ (set! int (substring int (string-length head) 3))
+ (cond
+ ((string-equal head "000")
+ (make_number int))
+ ((or (string-equal head "1")
+ (string-equal head "001"))
+ (string-append
+ "tuhat "
+ (make_number int)))
+ (t
+ (string-append
+ (make_number2 head)
+ "tuhatta "
+ (make_number int)))))
+ (t
+ (make_number2 int)))))
+
+(define (make_number2 int)
+ "(make_number2 INT)
+Converts an up-to-three digit sequence into a number."
+
+ (let (ones dozens hundreds output)
+ (cond
+ ((= (string-length int) 3)
+ (set! hundreds (substring int 0 1))
+ (set! dozens (substring int 1 1))
+ (set! ones (substring int 2 1)))
+ ((= (string-length int) 2)
+ (set! hundreds "0")
+ (set! dozens (substring int 0 1))
+ (set! ones (substring int 1 1)))
+ (t
+ (set! hundreds "0")
+ (set! dozens "0")
+ (set! ones (substring int 0 1))))
+ ;; HUNDREDS
+ (cond
+ ((string-equal hundreds "0")
+ (set! output ""))
+ ((string-equal hundreds "1")
+ (set! output "sata"))
+ (t
+ (set! output (string-append (number_list hundreds) "sataa"))))
+ ;; DOZENS & ONES
+ (cond
+ ((string-equal dozens "0")
+ (set! output (string-append output (number_list ones))))
+ ((string-equal dozens "1")
+ (if (string-equal ones "0")
+ (set! output (string-append output "kymmenen"))
+ (set! output (string-append output (number_list ones) "toista"))))
+ (t
+ (set! output (string-append output
+ (number_list dozens) "kymment"
+ (number_list ones)))))
+ output))
+
+
+
+(define (number_list digit)
+ "(number_list DIGIT)
+Returns the corresponding string for a given DIGIT"
+ (cond
+ ((string-equal digit "9") "yhdeksn")
+ ((string-equal digit "8") "kahdeksan")
+ ((string-equal digit "7") "seitsemn")
+ ((string-equal digit "6") "kuusi")
+ ((string-equal digit "5") "viisi")
+ ((string-equal digit "4") "nelj")
+ ((string-equal digit "3") "kolme")
+ ((string-equal digit "2") "kaksi")
+ ((string-equal digit "1") "yksi")
+ (t
+ "")))
+
+
+(define (finnish_tosyl_brackets phones accent)
+ "(finnish_tosyl_brackets phones)
+Takes a list of phones containing - as syllable boundary.
+Should we add a compound boundary? Probably...
+Construct the Festival bracket structure.
+Used by finnish_lts-function."
+ (let ((tavu nil) (syls nil) (p phones) (stress 0) (syltotal 1)
+ (cvcvcvcv nil)
+ (which 1) (secondary_stress 0))
+ ;; lasketaan tavujen mr
+ (while p
+ (if (eq? '- (car p))
+ (begin
+ (set! tavu (reverse tavu))
+ ;; if the 3rd syllable has 1 "mora"
+ ;; the secondary stress goes to the 4th syllable
+ (if (and (= syltotal 3)
+ (= (mora2 tavu) 1)
+ (or (string-matches (cadr p)
+ "^[abdefghijklmnoprstuvy@7NT]$")
+ (string-matches (cadr p) "^[aeiouy@7]:?$" )))
+ ;; had but 1 mora
+ (begin
+ ;; cvcvcvcv takes care of 4-syl words
+ ;; with a short 3rd syl
+ (set! cvcvcvcv t)
+ (set! secondary_stress 4)))
+ (if (and (= secondary_stress 4)
+ (= syltotal 4)
+ (= (mora2 tavu) 1)
+ (or (string-matches ;; short
+ (cadr p)
+ "^[abdefghijklmnoprstuvy@7NT]$" )
+ (string-matches (cadr p) "^[aeiouy@7]:?$" )))
+ (set! secondary_stress 3))
+
+
+
+ (set! syltotal (+ syltotal 1)) ;; N:s tavu alkaa
+
+ (set! tavu nil))
+ ;; muuten lis tavu
+ (set! tavu (cons (car p) tavu)))
+ (set! p (cdr p)))
+
+
+ (set! p phones)
+ (if (and (> syltotal 3) ;; secondary_stress is possible
+ (> accent 0)) ;; the word is stressed
+ ;; ON SECONDARY_STRESS
+ (begin
+ ;; 4-tavuinen, jossa 3:s oli lyhyt omaa vrn arvon, korjataan:
+ (if (and (= syltotal 4)
+ cvcvcvcv)
+ (set! secondary_stress 3))
+ ;; tarpeeksi pitk secondary_stresslliselle, mutta secondary_stress ei pll:
+ (if (= secondary_stress 0)
+ (set! secondary_stress 3)));; nyt aina kolmannelle tavulle
+ (set! secondary_stress 0))
+
+ (set! which 1)
+ (while p
+ (set! tavu nil)
+ (set! stress accent)
+ ;; asetetaan secondary_stress, jos on tarvis
+
+ (if (and (= which secondary_stress)
+ (> syltotal secondary_stress))
+ (begin
+ (set! secondary_stress (+ secondary_stress 2))
+ (set! stress 1)))
+
+ (while (and p
+ (not (eq? '- (car p))))
+ ;;;(set! name (list2string (cons (car p) syl)))
+ (set! tavu (cons (car p) tavu))
+ ;;;(item.set_name syl name)
+ (set! p (cdr p)))
+ (set! which (+ which 1))
+ (set! p (cdr p)) ;; hypp '-':n yli
+ (set! accent 0) ;; jlkitavuille
+ (set! syls (cons (list (reverse tavu) stress) syls)))
+ (reverse syls)))
+
+(define (mora2 list_of_phones)
+"(mora2 list_of_phones)
+Counts the moras (morae?) in a given list of phones.
+Does not support ambisyllabic long consonants."
+(let ((onset t)
+ (total 0)
+ phone)
+
+ (while list_of_phones
+ (set! phone (car list_of_phones))
+ ;; as long as we get Cs we're in the onset
+ (if (not (and onset
+ (string-matches phone "^[bdfghjklmnprstvNT]:?$" )))
+ (begin
+ (set! onset nil)
+ (if (string-matches phone "^[abdefghijklmnoprstuvy@7NT]:$" )
+ (set! total (+ total 2)) ;; long
+ (set! total (+ total 1))))) ;; short
+ (set! list_of_phones (cdr list_of_phones)))
+ total))
+
+
+
+(define (compound_stress compound)
+ "(compound_stress WORD)
+Handles the exception stress placement in compounds.
+The few compounds supported are recognized by the '-' separator.
+However secondary word stress did not show up in duration and intonation
+models... We could also add boundary detection based on vowel positions
+in neighboring syllables."
+
+ (let ((suitable (string-matches compound "^\\([A-Za-z][A-Za-z]+\-\\)+[A-Za-z][A-Za-z]+$"))
+ (word1 "")
+ (word2 nil)) ;; word2 will be a list
+ (if (not suitable) (set! word1 compound))
+ (while (and (> (string-length compound) 0)
+ suitable)
+ ;; compound marker has been found yet
+ (if (string-equal (substring compound 0 1) "-")
+ (begin
+ ;; behead the compound
+ (if (= (string-length compound) 1)
+ (set! compound "")
+ (set! compound (substring compound 1 (- (string-length compound) 1))))
+ (if (not (string-equal word1 ""))
+ (set! word2
+ (append word2 (finnish_tosyl_brackets
+ (lts.apply
+ (lts.apply
+ (lts.apply word1 'normalize)
+ 'finnish_cv)
+ 'remove_unneeded) 2))))
+
+ (set! word1 ""))
+ ;; else
+ (begin
+ (set! word1 (string-append word1 (substring compound 0 1)))
+ (if (= (string-length compound) 1)
+ (set! compound "")
+ (set! compound (substring compound 1 (- (string-length compound) 1))))))) ;; end of while
+
+ (if word2
+ (set! word2 (append word2
+ (finnish_tosyl_brackets
+ (lts.apply
+ (lts.apply
+ (lts.apply word1 'normalize)
+ 'finnish_cv)
+ 'remove_unneeded) 2)))
+ (set! word2 (finnish_tosyl_brackets
+ (lts.apply
+ (lts.apply
+ (lts.apply word1 'normalize)
+ 'finnish_cv)
+ 'remove_unneeded) 2)))
+ word2))
+
+;;;=======================================================================
+
+(lts.ruleset
+ normalize
+ ; sets
+ ( ( NUMERO 0 1 2 3 4 5 6 7 8 9 )
+ ( POIS "\"" "\'" "\`" )
+
+ ( CON b c d f g h j k l m n p q r s t v w x z
+ B C D F G H J K L M N P Q R S T V W X Z)
+ ( VOW a e i o u y
+ A E I O U Y )
+ ( LET A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+ a b c d e f g h i j k l m n o p q r s t u v w x y z )
+ )
+;
+; ;rules
+ (
+
+ ;; a lone "
+ ( # [ "\"" ] # = l a i n a u s m e r k k i )
+ ( # [ POIS ] # = h e i t t o m e r k k i )
+ ; seuraavat pois:
+ ( [ POIS ] = )
+ ( [ " " ] = ) ;; tokenisoija ei viel jaa merkkijonoa wordlistaksi...
+
+ ( [ 1 ] = y k s i )
+ ( [ 2 ] = k a k s i )
+ ( [ 3 ] = k o l m e )
+ ( [ 4 ] = n e l j @ )
+ ( [ 5 ] = v i i s i )
+ ( [ 6 ] = k u u s i )
+ ( [ 7 ] = s e i t s e m @ n )
+ ( [ 8 ] = k a h d e k s a n )
+ ( [ 9 ] = y h d e k s @ n )
+ ( [ 0 ] = n o l l a )
+
+ ( [ "#" ] = r i s u a i t a )
+ ( [ "$" ] = d o l l a r i )
+ ( [ "%" ] = p r o s e n t t i )
+ ( [ "&" ] = e t )
+
+ ;; should these be spoken (SayText "(word)")
+ ( [ "(" ] = v a s e n s u l k u )
+ ( [ ")" ] = o i k e a s u l k u )
+
+ ( [ * ] = a s t e r i s k i )
+ ( [ + ] = p l u s )
+ ;( [ "\/" = j a k o v i i v a )
+
+
+ ( # [ - ] # = v i i v a )
+ ( LET [ - ] LET = ) ;; morphemeboundary
+ ( LET [ - ] # = ) ;; word- => word
+ ( # [ - ] LET = ) ;; -word => word
+ ( [ - ] NUMERO = m i i n u s - )
+
+;; ( # [ - ] = )
+;; ( [ " " - " " ] = )
+;; ( " " [ - ] = )
+;; ( [ - ] # = )
+;; ( [ - ] " " = )
+
+ ( [ - ] = v i i v a )
+
+ ( [ "~" ] = a a l t o v i i v a )
+ ( [ _ ] = a l a v i i v a )
+ ( [ "^" ] = h a t t u )
+ ( [ "!" ] = h u u t o m e r k k i )
+ ( [ "/" ] = k a u t t a )
+ ( [ "\\" ] = k e n o v i i v a ) ;; kenoviiva kannattaa laventaa etukteen..
+ ( [ "?" ] = k y s y m y s m e r k k i )
+ ( [ \] ] = o i k e a h a k a s u l k u ) ;; finnish_lts ongelma
+ ( [ "}" ] = o i k e a k a a r i s u l k u )
+ ( [ "=" ] = o n y h t a k u i n )
+ ( [ "<" ] = p i e n e m p i k u i n )
+ ( [ "," ] = p i l k k u )
+ ( [ "" ] = p u n t a )
+ ( [ ";" ] = p u o l i p i s t e )
+ ( [ "|" ] = p y s t y v i i v a )
+ ( [ ">" ] = s u u r e m p i k u i n )
+ ( [ "[" ] = v a s e n h a k a s u l k u ) ;; finnish_lts ongelma
+ ( [ "{" ] = v a s e n k a a r i s u l k u ) ;; "{}" toimii oudosti...
+ ( [ "@" ] = @ t )
+
+ ( [ "." ] = p i s t e ) ;; token2words temppuilee
+ ( [ ":" ] i n # = )
+ ( [ ":" ] = k a k s o i s p i s t e )
+ ( [ " " ] = " " ) ;; separeted chars use this
+
+
+
+ ; # SH-nne
+ ( [ s c h ] = S ) ; schubert
+ ( [ S c h ] = S )
+ ( t [ s h ] = s ) ; tshetsheeni
+ ( T [ s h ] = s )
+ ( [ s h ] CON = S ) ; pushkin
+ ( [ S h ] = S )
+ ( VOW VOW [ s h ] = s h ) ; talOUSHallinto
+ ( [ s h ] y = s h ) ;
+ ( [ s h ] = s h ) ; mieshn
+ ( [ s h ] = s h ) ; ykkshrh
+ ( i l a [ s h ] = s h ) ; sotilashenkil
+ ( l l i [ s h ] = s h ) ; paikallishallinto
+ ( s k u [ s h ] = s h ) ; keskushallinto
+ ( n n u [ s h ] = s h ) ;
+ ( t u [ s h ] = s h ) ; opetushallitus
+ ( y [ s h ] = s h ) ; yrityshautomo
+ ( [ s h ] = s h ) ; seivshyppy
+ ( [ s h ] = s h ) ; ykkshenkil
+ ( # [ s h ] = S ) ; shakki
+ ( [ s h ] # = S ) ; bush
+ ( e i [ s h ] = s h ) ; yhteishenki
+ ( [ s h ] i # = S ) ; takeshi
+ ( w a [ s h ] i n g t = S S ) ; washington
+ ( [ s h ] o w = S )
+ ( m u [ s h ] = S ) ; kokoomushan
+ ( i h m i [ s h ] = s h ) ; ihmishenki
+ ( [ s h ] = S )
+
+;; ( [ a h l ] = a a l )
+ ( [ t z ] = t s )
+
+
+
+
+ ( [ ] = a ) ( [ ] = a )
+ ( [ ] = a ) ( [ ] = a )
+ ( [ ] = a ) ( [ "" ] = a )
+ ( [ ] = a ) ( [ ] = a )
+ ( [ ] = @ ) ( [ ] = @ )
+ ( [ ] = s ) ( [ ] = s )
+ ( [ ] = t h ) ( [ ] = t h )
+ ( [ ] = e ) ( [ ] = e )
+ ( [ ] = e ) ( [ ] = e )
+ ( [ ] = e ) ( [ ] = e )
+ ( [ ] = e ) ( [ ] = e )
+ ( [ ] = i ) ( [ ] = i )
+ ( [ ] = i ) ( [ ] = i )
+ ( [ ] = i ) ( [ ] = i )
+ ( [ ] = i ) ( [ ] = i )
+ ( [ ] = n j ) ( [ ] = n j )
+ ( [ ] = 7 ) ( [ ] = 7 )
+ ( [ ] = o ) ( [ ] = o )
+ ( [ ] = o ) ( [ ] = o )
+ ( [ ] = o ) ( [ ] = o )
+ ( [ ] = o ) ( [ ] = o )
+ ( [ ] = s s )
+ ( [ ] = t h ) ( [ ] = t h )
+ ( [ ] = u ) ( [ ] = u )
+ ( [ ] = u ) ( [ ] = u )
+ ( [ ] = u ) ( [ ] = u )
+ ( [ ] = y ) ( [ ] = y )
+ ( [ ] = y ) ( [ ] = y )
+ ( [ ] = y )
+
+ ; "lowercase"
+ ( [ a ] = a ) ( [ b ] = b )
+ ( [ A ] = a ) ( [ B ] = b )
+
+ ( [ c ] = c )
+ ( [ C ] = c )
+
+ ( [ d ] = d ) ( [ e ] = e )
+ ( [ D ] = d ) ( [ E ] = e )
+ ( [ f ] = f ) ( [ g ] = g ) ( [ h ] = h ) ( [ i ] = i ) ( [ j ] = j )
+ ( [ F ] = f ) ( [ G ] = g ) ( [ H ] = h ) ( [ I ] = i ) ( [ J ] = j )
+
+ ( [ K ] = k ) ( [ L ] = l ) ( [ M ] = m )
+ ( [ N ] = n )
+ ( [ k ] = k ) ( [ l ] = l ) ( [ m ] = m )
+
+ ( [ n ] = n )
+
+ ( [ O ] = o ) ( [ P ] = p ) ( [ Q ] = q ) ( [ R ] = r ) ( [ S ] = s )
+ ( [ o ] = o ) ( [ p ] = p ) ( [ q ] = q ) ( [ r ] = r ) ( [ s ] = s )
+ ( [ T ] = t ) ( [ U ] = u ) ( [ V ] = v ) ( [ W ] = w ) ( [ X ] = x )
+ ( [ t ] = t ) ( [ u ] = u ) ( [ v ] = v ) ( [ w ] = w ) ( [ x ] = x )
+ ( [ Y ] = y ) ( [ Z ] = z ) ( [ ] = ) ( [ ] = @ ) ( [ ] = 7 )
+ ( [ y ] = y ) ( [ z ] = z ) ( [ ] = ) ( [ ] = @ ) ( [ ] = 7 )
+
+ ))
+
+(lts.ruleset
+ finnish_cv
+ ; sets
+ (( LAITONA e o y @ 7 )
+ ( LAITONEI a o y @ 7 )
+ ( LAITONOU a e y @ 7 )
+ ( LAITONY7 a e o u @ )
+ ( LAITON@ a e u o 7 )
+ ( VOW a e i o u y @ 7 )
+ ( CON b c d f g h j k l m n p q r s t v w x z )
+ )
+ ;rules
+ (
+; ( # [ s h ] = __ S )
+; ( # [ s c h ] = __ S )
+ ( # [ t h ] = __ T )
+ ( [ t h ] # = __ T ) ;; cheat
+ ( [ t h ] CON = __ T )
+
+ ( [ a - a ] = _ a - a )
+ ( [ e - e ] = _ e - e )
+ ( [ i - i ] = _ i - i )
+ ( [ o - o ] = _ o - o )
+ ( [ u - u ] = _ u - u )
+ ( [ y - i ] = _ y - y )
+ ( [ @ - @ ] = _ @ - @ )
+ ( [ 7 - 7 ] = _ 7 - 7 )
+
+
+ ( [ a ] LAITONA = _ a - )
+ ;; ( [ e ] a # = _ e )
+ ( [ e ] LAITONEI = _ e - )
+ ;; ( [ i ] a # = _ i )
+ ( [ i ] LAITONEI = _ i - )
+ ;;( [ o ] a # = _ o )
+ ( [ o ] LAITONOU = _ o - )
+ ( [ u ] LAITONOU = _ u - )
+ ( [ y ] LAITONY7 = _ y - )
+ ;; ( [ 7 ] # _ 7 )
+ ( [ 7 ] LAITONY7 = _ 7 - )
+ ( [ @ ] LAITON@ = _ @ - )
+
+ ;; some assimilations
+ ( VOW [ n m ] VOW = __ m: )
+ ( VOW [ n ] p VOW = m )
+ ( [ n g ] VOW = __ N: )
+ ( [ n g ] = __ N )
+ ( [ n ] k = __ N )
+
+
+
+ ( [ a a ] = _ a: )
+ ( [ b b ] = "__" b: )
+ ( [ c c ] = "__" k: ) ( [ c k ] = k: )
+ ( [ d d ] = "__" d: )
+ ( [ e e ] = _ e: )
+ ( [ f f ] = "__" f: )
+ ( [ g g ] = "__" g: )
+ ( [ h h ] = "__" h: )
+ ( [ i i ] = _ i: )
+ ( [ j j ] = "__" j: )
+ ( [ k k ] = "__" k: )
+ ( [ l l ] = "__" l: )
+ ( [ m m ] = "__" m: )
+ ( [ n n ] = "__" n: )
+ ( [ o o ] = _ o: )
+ ( [ p p ] = "__" p: )
+ ( [ r r ] = "__" r: )
+ ( [ s s ] = "__" s: )
+ ( [ S S ] = "__" S: )
+ ( [ t t ] = "__" t: )
+ ( [ u u ] = _ u: )
+ ( [ v v ] = "__" v: )
+ ( [ y y ] = _ y: )
+ ( [ @ @ ] = _ @: )
+ ( [ 7 7 ] = _ 7: )
+
+ ( [ a ] = _ a )
+ ( [ b ] = __ b )
+ ( [ c ] e = __ s )
+ ( [ c ] = __ k )
+ ( [ d ] = __ d )
+ ( [ e ] = _ e )
+ ( [ f ] = __ f )
+ ( [ g ] = __ g )
+ ( [ h ] = __ h )
+
+ ( [ i ] = _ i )
+ ( [ j ] = __ j )
+ ( [ k ] = __ k )
+ ( [ l ] = __ l )
+ ( [ m ] = __ m )
+ ( [ n ] = __ n )
+ ( [ o ] = _ o )
+ ( [ p ] = __ p )
+ ( # [ q u ] = k v )
+ ( [ q u ] = - k v )
+ ( # [ q ] = k v )
+ ( [ q ] = - k v ) ; frek-venssi
+ ( [ r ] = __ r )
+ ( [ s ] = __ s )
+ ( [ t ] = __ t )
+ ( [ u ] = _ u )
+ ( [ v ] = __ v )
+ ( [ w ] = __ v )
+ ( [ x ] = __ k __ s ) ; tak-si
+ ( [ y ] = _ y )
+ ( # [ z ] = t s )
+ ( [ z ] = - t s )
+ ( [ ] = _ o )
+ ( [ @ ] = _ @ )
+ ( [ 7 ] = _ 7 )
+ ( [ - ] = - )
+ ( [ L ] = __ L ) ;; this is our light /l/
+ ( [ S ] = __ S ) ;; this is our palatal /s/
+ ( [ " "+ ] = " " )
+))
+
+(lts.ruleset remove_unneeded
+ ( ; sets
+ ( CON b d f g h j k l m n p r s t v N T S L
+ b: d: f: g: h: j: k: l: m: n: p: r: s: t: v: N: T: S: L:)
+ ( VOW a e i o u y @ 7 a: e: i: o: u: y: @: 7: )
+ ( LONG a: e: i: o: u: y: @: 7: )
+ ( EOS # " " )
+ )
+ ( ; rules
+ ( [ - _ ] = - )
+ ( [ - __ ] = - )
+
+ ( EOS __ CON __ CON __ CON [ __ ] = )
+ ( EOS __ CON __ CON [ __ ] = )
+ ( EOS __ CON [ __ ] = )
+ ( EOS [ __ ] = )
+ ( [ __ ] CON _ VOW = - )
+ ( [ __ ] = )
+
+ ( EOS [ _ ] = )
+ ( CON [ _ ] = )
+ ( - [ _ ] = )
+ ( LONG [ _ ] = - )
+ ( [ _ a _ ] = a - )
+ ( [ _ e _ ] = e - )
+ ( [ _ i _ ] = i - )
+ ( [ _ o _ ] = o - )
+ ( [ _ u _ ] = u - )
+ ( [ _ y _ ] = y - )
+ ( [ _ @ _ ] = @ - )
+ ( [ _ 7 _ ] = 7 - )
+ ( [ _ ] = )
+
+ ( [ a: ] = a: )
+ ( [ b: ] __ CON = b ) ( [ b: ] # = b ) ( # __ [ b: ] = b ) ( [ b: ] = b: )
+ ( [ d: ] __ CON = d ) ( [ d: ] # = d ) ( # __ [ d: ] = d ) ( [ d: ] = d: )
+ ( [ e: ] = e: )
+ ( [ f: ] __ CON = f ) ( [ f: ] # = f ) ( # __ [ f: ] = f ) ( [ f: ] = f: )
+ ( [ g: ] __ CON = g ) ( [ g: ] # = g ) ( # __ [ g: ] = g ) ( [ g: ] = g: )
+ ( [ h: ] __ CON = h ) ( [ h: ] # = h ) ( # __ [ h: ] = h ) ( [ h: ] = h: )
+ ( [ i: ] = i: )
+ ( [ j: ] __ CON = j ) ( [ j: ] # = j ) ( # __ [ j: ] = j ) ( [ j: ] = j: )
+ ( [ k: ] __ CON = k ) ( [ k: ] # = k ) ( # __ [ k: ] = k ) ( [ k: ] = k: )
+ ( [ l: ] __ CON = l ) ( [ l: ] # = l ) ( # __ [ l: ] = l ) ( [ l: ] = l: )
+ ( [ m: ] __ CON = m ) ( [ m: ] # = m ) ( # __ [ m: ] = m ) ( [ m: ] = m: )
+ ( [ n: ] __ CON = n ) ( [ n: ] # = n ) ( # __ [ n: ] = n ) ( [ n: ] = n: )
+ ( [ N: ] __ CON = N ) ( [ N: ] # = N ) ( # __ [ N: ] = N ) ( [ N: ] = N: )
+ ( [ o: ] = o: )
+ ( [ p: ] __ CON = p ) ( [ p: ] # = p ) ( # __ [ p: ] = p ) ( [ p: ] = p: )
+ ( [ r: ] __ CON = r ) ( [ r: ] # = r ) ( # __ [ r: ] = r ) ( [ r: ] = r: )
+ ( [ s: ] __ CON = s ) ( [ s: ] # = s ) ( # __ [ s: ] = s ) ( [ s: ] = s: )
+ ( [ t: ] __ CON = t ) ( [ t: ] # = t ) ( # __ [ t: ] = t ) ( [ t: ] = t: )
+ ( [ u: ] = u: )
+ ( [ v: ] __ CON = v ) ( [ v: ] # = v ) ( # __ [ v: ] = v ) ( [ v: ] = v: )
+ ( [ y: ] = y: )
+ ( [ @: ] = @: )
+ ( [ 7: ] = 7: )
+ ( [ L: ] __ CON = L ) ( [ L: ] # = L ) ( # __ [ L: ] = L ) ( [ L: ] = L: ) ;; our light /l/
+ ( [ S: ] __ CON = S ) ( [ S: ] # = S ) ( # __ [ S: ] = S ) ( [ S: ] = S: ) ;; our palatal /s/
+ ( [ T: ] __ CON = T ) ( [ T: ] # = T ) ( # __ [ T: ] = T ) ( [ T: ] = T: )
+ ( [ D: ] __ CON = D ) ( [ D: ] # = D ) ( # __ [ D: ] = D ) ( [ D: ] = D: )
+
+ ;;; short (these are the original rules)
+ ( [ a ] = a ) ( [ b ] = b ) ( [ d ] = d ) ( [ e ] = e )
+ ( [ f ] = f ) ( [ g ] = g ) ( [ h ] = h ) ( [ i ] = i ) ( [ j ] = j )
+ ( [ k ] = k ) ( [ l ] = l ) ( [ m ] = m ) ( [ n ] = n ) ( [ o ] = o )
+ ( [ p ] = p ) ( [ q ] = q ) ( [ r ] = r ) ( [ s ] = s ) ( [ t ] = t )
+ ( [ u ] = u ) ( [ v ] = v ) ( [ y ] = y )
+ ( [ @ ] = @ ) ( [ ] = ) ( [ 7 ] = 7 ) ( [ z ] = z )
+ ( [ - ] = - )
+ ( [ L ] = L ) ;; this is our light /l/
+ ( [ S ] = S ) ;; this is our palatal /s/
+ ( [ T ] = T )
+ ( [ D ] = D )
+ ( [ N ] = N )
+ ( [ _ ] = _ ) ( [ __ ] = __ )
+ ( [ " " ] = "" ) ;; cheat for LSEQs
+ ))
+
+
+(provide 'finnish_lts)
+
+
+