diff --git a/app/src/main/java/com/grammatek/simaromur/AppRepository.java b/app/src/main/java/com/grammatek/simaromur/AppRepository.java index 3d3cd61b..32c32edf 100644 --- a/app/src/main/java/com/grammatek/simaromur/AppRepository.java +++ b/app/src/main/java/com/grammatek/simaromur/AppRepository.java @@ -28,6 +28,7 @@ import com.grammatek.simaromur.db.Voice; import com.grammatek.simaromur.db.VoiceDao; import com.grammatek.simaromur.device.DownloadVoiceManager; +import com.grammatek.simaromur.device.SymbolsLvLIs; import com.grammatek.simaromur.device.TTSAudioControl; import com.grammatek.simaromur.device.TTSEngineController; import com.grammatek.simaromur.device.pojo.DeviceVoice; @@ -901,8 +902,10 @@ public CacheItem executeFrontendAndSaveIntoCache(String text, CacheItem item, co // we always need to normalize the text, but it doesn't hurt, if we always do G2P as well // for network voices, this is currently all that is needed. But there is an audible // problem with trailing "." though, so we remove it - final String normalizedText = mFrontend.getNormalizationManager().process(text).replaceAll("\\.+$", ""); + String normalizedText = mFrontend.getNormalizationManager().process(text).replaceAll("\\.+$", ""); final String phonemes = mFrontend.transcribe(normalizedText, voice.type, voice.version); + // prevent the network voices from pronouncing 'sil' + normalizedText = normalizedText.replaceAll(SymbolsLvLIs.TagPause, ","); Log.v(LOG_TAG, "onSynthesizeText: original (\"" + text + "\"), normalized (\"" + normalizedText + "\"), phonemes (\"" + phonemes + "\")"); Utterance updatedUtterance = UtteranceCacheManager.newUtterance(text, normalizedText, List.of(phonemes)); item = mUtteranceCacheManager.saveUtterance(updatedUtterance); diff --git a/app/src/main/java/com/grammatek/simaromur/device/SymbolsLvLIs.java b/app/src/main/java/com/grammatek/simaromur/device/SymbolsLvLIs.java index e5b3308f..65d6097c 100644 --- a/app/src/main/java/com/grammatek/simaromur/device/SymbolsLvLIs.java +++ b/app/src/main/java/com/grammatek/simaromur/device/SymbolsLvLIs.java @@ -47,6 +47,9 @@ public enum Type { private final static String SymbolsSpecial = SymbolShortPause + " " + SymbolSpokenNoise + " " + SymbolSilence; + // tags + public final static String TagPause = ""; + // IPA symbols as HashMap private static final HashMap IPASymbolMap; static { diff --git a/app/src/main/java/com/grammatek/simaromur/frontend/NormalizationManager.java b/app/src/main/java/com/grammatek/simaromur/frontend/NormalizationManager.java index a9323fbf..10b387dd 100644 --- a/app/src/main/java/com/grammatek/simaromur/frontend/NormalizationManager.java +++ b/app/src/main/java/com/grammatek/simaromur/frontend/NormalizationManager.java @@ -3,6 +3,8 @@ import android.content.Context; import android.util.Log; +import com.grammatek.simaromur.device.SymbolsLvLIs; + import opennlp.tools.postag.POSModel; import opennlp.tools.postag.POSTaggerME; @@ -75,11 +77,11 @@ private List normalize(final List tokenized) { // Some very basic phrasing for longer sentences // TODO: improve! if (tags.length >= 10) { - postNormalized = postNormalized.replace(" og ", " og "); - postNormalized = postNormalized.replace(" en ", " en "); - postNormalized = postNormalized.replace(" þegar ", " þegar "); - postNormalized = postNormalized.replace(" sem ", " sem "); - postNormalized = postNormalized.replace(" ef ", " ef "); + postNormalized = postNormalized.replace(" og ", " " + SymbolsLvLIs.TagPause + " og "); + postNormalized = postNormalized.replace(" en ", " " + SymbolsLvLIs.TagPause + " en "); + postNormalized = postNormalized.replace(" þegar ", " " + SymbolsLvLIs.TagPause + " þegar "); + postNormalized = postNormalized.replace(" sem ", " " + SymbolsLvLIs.TagPause + " sem "); + postNormalized = postNormalized.replace(" ef ", " " + SymbolsLvLIs.TagPause + " ef "); } normalized.add(postNormalized); } diff --git a/app/src/main/java/com/grammatek/simaromur/frontend/Pronunciation.java b/app/src/main/java/com/grammatek/simaromur/frontend/Pronunciation.java index bb10790c..dba31d77 100644 --- a/app/src/main/java/com/grammatek/simaromur/frontend/Pronunciation.java +++ b/app/src/main/java/com/grammatek/simaromur/frontend/Pronunciation.java @@ -129,7 +129,6 @@ public String convert(String transcribed, String fromAlphabet, String toAlphabet @NonNull private String transcribeString(String text, boolean isFlitev02) { - final String silToken = ""; String[] tokens = text.split(" "); StringBuilder sb = new StringBuilder(); for (String tok : tokens) { @@ -139,7 +138,7 @@ private String transcribeString(String text, boolean isFlitev02) { else if (mPronDict.containsKey(tok)) { transcr = mPronDict.get(tok).getTranscript().trim(); } - else if (tok.equals(silToken)){ + else if (tok.equals(SymbolsLvLIs.TagPause)){ transcr = SymbolsLvLIs.SymbolShortPause; } else { @@ -154,6 +153,10 @@ else if (tok.equals(silToken)){ if (isFlitev02 && transcr.matches(".+s I n s")) transcr = transcr.replaceAll("s I n s", "s I n n s"); + // bug in Thrax grammar, catch the error here: insert space before C if missing + // like in 'Vilhjálmsdóttur' -> 'v I lC au l m s t ou h t Y r' + // TODO: remove when Thrax grammar is fixed! + transcr = transcr.replaceAll("([a-zA-Z])C", "$1 C"); sb.append(transcr).append(" "); } return sb.toString().trim(); diff --git a/app/src/main/java/com/grammatek/simaromur/frontend/TTSNormalizer.java b/app/src/main/java/com/grammatek/simaromur/frontend/TTSNormalizer.java index 2e9fa5c6..69d484da 100644 --- a/app/src/main/java/com/grammatek/simaromur/frontend/TTSNormalizer.java +++ b/app/src/main/java/com/grammatek/simaromur/frontend/TTSNormalizer.java @@ -4,6 +4,8 @@ import androidx.annotation.NonNull; +import com.grammatek.simaromur.device.SymbolsLvLIs; + import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -297,7 +299,7 @@ else if (numberToken.matches(NumberHelper.FRACTION_PTRN)) { part2 = normalizeThousandDigit(part2, nextTag); else part2 = normalizeNumber(part2, nextTag); - normalized = part1 + " " + part2; + normalized = part1 + " " + SymbolsLvLIs.TagPause + " " + part2; } // 01. (what kind of ordinal is this?) else if (numberToken.matches("^0\\d\\.$")) { @@ -473,7 +475,7 @@ private String normalizeDigitOrdinal(String token) { * nominative representation, also '+', '/', ':' are replaced. */ private String normalizeDigits(String token) { - token = token.replaceAll(" ", " "); + token = token.replaceAll(" ", SymbolsLvLIs.TagPause + " "); for (String digit : NumberHelper.DIGIT_NUMBERS.keySet()) { final String replacement = NumberHelper.DIGIT_NUMBERS.get(digit); if (replacement != null) { diff --git a/app/src/test/java/com/grammatek/simaromur/NormalizationManagerTest.java b/app/src/test/java/com/grammatek/simaromur/NormalizationManagerTest.java index c5442a44..644202a5 100644 --- a/app/src/test/java/com/grammatek/simaromur/NormalizationManagerTest.java +++ b/app/src/test/java/com/grammatek/simaromur/NormalizationManagerTest.java @@ -156,37 +156,37 @@ private Map getTestSentences() { "Í gær greindust sjötíu og átta með a b c d nítján .".toLowerCase()); testSentences.put("þetta stóð í 4. gr. laga.", "þetta stóð í fjórðu grein laga .".toLowerCase()); testSentences.put("Að jafnaði koma daglega um 48 rútur í Bláa Lónið .", - "Að jafnaði koma daglega um fjörutíu og átta rútur í Bláa Lónið .".toLowerCase()); + "Að jafnaði koma daglega um fjörutíu og átta rútur í Bláa Lónið .".toLowerCase()); // should be sport domain, for now we can only set domain=sport manually (where the hyphen // is replaced with a space instead of "til") testSentences.put("Áfram hélt fjörið í síðari hálfleik og þegar 3. leikhluti var tæplega hálfnaður var staðan 64-52 .", - "Áfram hélt fjörið í síðari hálfleik og þegar þriðji leikhluti var tæplega hálfnaður var staðan sextíu og fjögur til fimmtíu og tvö .".toLowerCase()); + "Áfram hélt fjörið í síðari hálfleik og þegar þriðji leikhluti var tæplega hálfnaður var staðan sextíu og fjögur til fimmtíu og tvö .".toLowerCase()); testSentences.put("Viðeignin fer fram í sal FS og hefst klukkan 20 .", - "Viðeignin fer fram í sal f s og hefst klukkan tuttugu .".toLowerCase()); // spelling error! + "Viðeignin fer fram í sal f s og hefst klukkan tuttugu .".toLowerCase()); // spelling error! testSentences.put("Annars var verði 3500 fyrir tímann !", "Annars var verði þrjú þúsund og fimm hundruð fyrir tímann .".toLowerCase()); // spelling error testSentences.put("Af því tilefni verða kynningar um allt land á hinum ýmsu deildum innann SL þriðjudaginn 18. janúar nk. ", "Af því tilefni verða kynningar um allt land á hinum ýmsu deildum innann s l þriðjudaginn átjánda janúar næstkomandi .".toLowerCase()); testSentences.put("„ Ég kíki daglega á facebook , karfan.is , vf.is , mbl.is , kkí , og utpabroncs.com . “ ", - ", Ég kíki daglega á facebook , karfan punktur is , v f punktur is , m b l punktur is , k k í , og utpabronks punktur com . ,".toLowerCase()); + ", Ég kíki daglega á facebook , karfan punktur is , v f punktur is , m b l punktur is , k k í , og utpabronks punktur com . ,".toLowerCase()); testSentences.put("Arnór Ingvi Traustason 57. mín. Jónas Guðni, sem er 33 ára, hóf fótboltaferil sinn árið 2001.", - "Arnór Ingvi Traustason fimmtugasta og sjöunda mínúta . Jónas Guðni , sem er þrjátíu og þriggja ára , hóf fótboltaferil sinn árið tvö þúsund og eitt .".toLowerCase()); + "Arnór Ingvi Traustason fimmtugasta og sjöunda mínúta . Jónas Guðni , sem er þrjátíu og þriggja ára , hóf fótboltaferil sinn árið tvö þúsund og eitt .".toLowerCase()); // correct version impossible, since the tagger tags "lóð" and "byggingarreit" as dative, causing "í einni lóð og einum byggingarreit" (regina original does that as well) //testSentences.put("Einnig er gert ráð fyrir að sameina lóðir og byggingarreiti við Sjávarbraut 1 - 7 í 1 lóð og 1 byggingarreit. Miðaverð fyrir fullorðna kr. 5500 ", // "Einnig er gert ráð fyrir að sameina lóðir og byggingarreiti við Sjávarbraut eitt til sjö í eina lóð og einn byggingarreit . Miðaverð fyrir fullorðna krónur fimm þúsund og fimm hundruð ."); testSentences.put("Einnig er gert ráð fyrir að sameina lóðir og byggingarreiti við Sjávarbraut 1 - 7 í 1 lóð og 1 byggingarreit. Miðaverð fyrir fullorðna kr. 5500 ", - "Einnig er gert ráð fyrir að sameina lóðir og byggingarreiti við Sjávarbraut eitt til sjö í einni lóð og einum byggingarreit . Miðaverð fyrir fullorðna krónur fimm þúsund og fimm hundruð .".toLowerCase()); + "Einnig er gert ráð fyrir að sameina lóðir og byggingarreiti við Sjávarbraut eitt til sjö í einni lóð og einum byggingarreit . Miðaverð fyrir fullorðna krónur fimm þúsund og fimm hundruð .".toLowerCase()); testSentences.put("Stolt Sea Farm (SSF), fiskeldisarmur norsku skipa- og iðnaðarsamstæðunnar Stolt-Nielsen, jók sölu sína á flatfiski um 53% á öðrum ársfjórðungi 2015.", - "Stolt Sea Farm , s s f , , fiskeldisarmur norsku skipa og iðnaðarsamstæðunnar Stolt Nielsen , jók sölu sína á flatfiski um fimmtíu og þrjú prósent á öðrum ársfjórðungi tvö þúsund og fimmtán .".toLowerCase()); + "Stolt Sea Farm , s s f , , fiskeldisarmur norsku skipa og iðnaðarsamstæðunnar Stolt Nielsen , jók sölu sína á flatfiski um fimmtíu og þrjú prósent á öðrum ársfjórðungi tvö þúsund og fimmtán .".toLowerCase()); testSentences.put("Í janúarbyrjun 1983 var stofnað nýtt hlutafélag, Víkurféttir ehf. sem tók við.", - "Í janúarbyrjun nítján hundruð áttatíu og þrjú var stofnað nýtt hlutafélag , Víkurféttir e h f sem tók við .".toLowerCase()); + "Í janúarbyrjun nítján hundruð áttatíu og þrjú var stofnað nýtt hlutafélag , Víkurféttir e h f sem tók við .".toLowerCase()); testSentences.put("Jarðskjálfti að stærð 3,9 varð fyrir sunnan Kleifarvatn kl. 19:50 í gærkvöldi.", "Jarðskjálfti að stærð þrír komma níu varð fyrir sunnan Kleifarvatn klukkan nítján fimmtíu í gærkvöldi .".toLowerCase()); // can't interpret "söfnuðu krónum", same error in regina original //testSentences.put("Stelpurnar Carmen Diljá Guðbjarnardóttir og Elenora Rós Georgsdóttir söfnuðu 7.046 kr.", // "Stelpurnar Carmen Diljá Guðbjarnardóttir og Elenora Rós Georgsdóttir söfnuðu sjö þúsund fjörutíu og sex krónum ."); testSentences.put("Stelpurnar Carmen Diljá Guðbjarnardóttir og Elenora Rós Georgsdóttir söfnuðu 7.046 kr.", - "Stelpurnar Karmen Diljá Guðbjarnardóttir og Elenora Rós Georgsdóttir söfnuðu sjö þúsund fjörutíu og sex krónur .".toLowerCase()); + "Stelpurnar Karmen Diljá Guðbjarnardóttir og Elenora Rós Georgsdóttir söfnuðu sjö þúsund fjörutíu og sex krónur .".toLowerCase()); testSentences.put("Hann skoraði 21 stig og tók 12 fráköst.", "Hann skoraði tuttugu og eitt stig og tók tólf fráköst .".toLowerCase()); testSentences.put("Opna Suðurnesjamótið í pílu fer fram þann 4. desember nk. kl. 13:00 í píluaðstöðu Pílufélags Reykjanesbæjar að Hrannargötu 6. ", "Opna Suðurnesjamótið í pílu fer fram þann fjórða desember næstkomandi klukkan þrettán núll núll ".toLowerCase() + @@ -195,42 +195,42 @@ private Map getTestSentences() { "Karlar eru rétt innan við tvö prósent hjúkrunarfræðinga á Íslandi .".toLowerCase()); // should be "sjö fimm sjö vélarnar" (same error in original regina) testSentences.put("Lendingarnar eru hlutfallslega svo fáar að elstu 757 -vélarnar eru aðeins hálfnaðar hvað líftíma varðar", - "Lendingarnar eru hlutfallslega svo fáar að elstu sjö hundruð fimmtíu og sjö vélarnar eru aðeins hálfnaðar hvað líftíma varðar .".toLowerCase()); + "Lendingarnar eru hlutfallslega svo fáar að elstu sjö hundruð fimmtíu og sjö vélarnar eru aðeins hálfnaðar hvað líftíma varðar .".toLowerCase()); testSentences.put("Á samanlögðu svæði Vesturlands og Vestfjarða voru 4.400 gistinætur sem jafngildir 7,5% fækkun milli ára.", - "Á samanlögðu svæði Vesturlands og Vestfjarða voru fjögur þúsund og fjögur hundruð gistinætur sem jafngildir sjö komma fimm prósent fækkun milli ára .".toLowerCase()); + "Á samanlögðu svæði Vesturlands og Vestfjarða voru fjögur þúsund og fjögur hundruð gistinætur sem jafngildir sjö komma fimm prósent fækkun milli ára .".toLowerCase()); testSentences.put("Elvar skilaði 22 stigum, þar af 5 af 8 í þriggjastiga.", - "Elvar skilaði tuttugu og tveimur stigum , þar af fimm af átta í þriggjastiga .".toLowerCase()); + "Elvar skilaði tuttugu og tveimur stigum , þar af fimm af átta í þriggjastiga .".toLowerCase()); // not possible to get correct looking at next tag, depends on "keyri", direct object in acc //testSentences.put("Ég keyri 2000 km á mánuði til og frá vinnu, þetta eru 20 - 25 stundir.", // "Ég keyri tvö þúsund kílómetra á mánuði til og frá vinnu , þetta eru tuttugu til tuttugu og fimm stundir ."); testSentences.put("Ég keyri 2000 km á mánuði til og frá vinnu, þetta eru 20 - 25 stundir.", - "Ég keyri tvö þúsund kílómetrar á mánuði til og frá vinnu , þetta eru tuttugu til tuttugu og fimm stundir .".toLowerCase()); + "Ég keyri tvö þúsund kílómetrar á mánuði til og frá vinnu , þetta eru tuttugu til tuttugu og fimm stundir .".toLowerCase()); // not possible tu get correct looking at next tag, depends on "Áfangastaðir". Also: should have a dictionary of // uppercase token not to separate, like "WOW" //testSentences.put("Áfangastaðir WOW air eru nú 31 talsins, 23 innan Evrópu en 8 talsins í Norður Ameríku.", // "Áfangastaðir WOW air eru nú þrjátíu og einn talsins , tuttugu og þrír innan Evrópu en átta talsins í Norður Ameríku ."); testSentences.put("Áfangastaðir WOW air eru nú 31 talsins, 23 innan Evrópu en 8 talsins í Norður Ameríku.", - "Áfangastaðir wow air eru nú þrjátíu og eins talsins , tuttugu og þrjú innan Evrópu en átta talsins í Norður Ameríku .".toLowerCase()); + "Áfangastaðir wow air eru nú þrjátíu og eins talsins , tuttugu og þrjú innan Evrópu en átta talsins í Norður Ameríku .".toLowerCase()); testSentences.put("Fyrstu félögin í Danmörku, Noregi og Svíþjóð 1919 og Norræna félagið á Íslandi 29. september árið 1922 .", - "Fyrstu félögin í Danmörku , Noregi og Svíþjóð nítján hundruð og nítján og Norræna félagið á Íslandi ".toLowerCase() + - "tuttugasta og níunda september árið nítján hundruð tuttugu og tvö .".toLowerCase()); + "Fyrstu félögin í Danmörku , Noregi og Svíþjóð nítján hundruð og nítján og Norræna félagið á Íslandi ".toLowerCase() + + "tuttugasta og níunda september árið nítján hundruð tuttugu og tvö .".toLowerCase()); testSentences.put("Vindmyllurnar eru hvor um sig 900 kW og samanlögð raforkuframleiðsla þeirra er áæetluð um 5,4 GWst á ári.", - "Vindmyllurnar eru hvor um sig níu hundruð kílóvött og samanlögð raforkuframleiðsla þeirra er áæetluð um ".toLowerCase() + + "Vindmyllurnar eru hvor um sig níu hundruð kílóvött og samanlögð raforkuframleiðsla þeirra er áæetluð um ".toLowerCase() + "fimm komma fjórar Gígavattstundir á ári .".toLowerCase()); // cannot get "ha" correct (reisa + acc) or "fm" (default: fermetrar, next tag: ')' ) regina does the same //testSentences.put("Hollenska fjárfestingafyrirtækið EsBro hyggst reisa 15 ha (150.000 m²) gróðurhús til framleiðslu á tómötum", // "Hollenska fjárfestingafyrirtækið EsBro hyggst reisa fimmtán hektara ( hundrað og fimmtíu þúsund fermetra ) gróðurhús til framleiðslu á tómötum"); testSentences.put("Hollenska fjárfestingafyrirtækið EsBro hyggst reisa 15 ha (150.000 m²) gróðurhús til framleiðslu á tómötum", - "Hollenska fjárfestingafyrirtækið EsBro hyggst reisa fimmtán hektarar , hundrað og fimmtíu þúsund fermetrar , gróðurhús til framleiðslu á tómötum .".toLowerCase()); + "Hollenska fjárfestingafyrirtækið EsBro hyggst reisa fimmtán hektarar , hundrað og fimmtíu þúsund fermetrar , gróðurhús til framleiðslu á tómötum .".toLowerCase()); testSentences.put("Mynd / elg@vf.is", "Mynd skástrik elg hjá v f punktur is .".toLowerCase()); - testSentences.put("hefur leikið sjö leiki með U-21 árs liðinu.", "hefur leikið sjö leiki með U tuttugu og eins árs liðinu .".toLowerCase()); - testSentences.put("er þetta í 23. skiptið sem mótið er haldið .", "er þetta í tuttugasta og þriðja skiptið sem mótið er haldið .".toLowerCase()); + testSentences.put("hefur leikið sjö leiki með U-21 árs liðinu.", "hefur leikið sjö leiki með U tuttugu og eins árs liðinu .".toLowerCase()); + testSentences.put("er þetta í 23. skiptið sem mótið er haldið .", "er þetta í tuttugasta og þriðja skiptið sem mótið er haldið .".toLowerCase()); testSentences.put("Skráning er hafin á http://keflavik.is/fimleikar/ og ef eitthvað er óljóst er hægt að hafa samband í síma 421-6368 eða á fimleikar@keflavik.is", "Skráning er hafin á keflavík punktur is skástrik ".toLowerCase() + - "fimleikar og ef eitthvað er óljóst er hægt að hafa samband í síma fjórir tveir einn sex þrír sex átta eða á fimleikar hjá keflavík punktur is .".toLowerCase()); + "fimleikar og ef eitthvað er óljóst er hægt að hafa samband í síma fjórir tveir einn sex þrír sex átta eða á fimleikar hjá keflavík punktur is .".toLowerCase()); testSentences.put("Austlæg átt, 5-13 m/s síðdegis.", "Austlæg átt , fimm til þrettán metrar á sekúndu síðdegis .".toLowerCase()); testSentences.put("hlutfallið á Vestfjörðum þar sem 14,1% íbúa eru innflytjendur", - "hlutfallið á Vestfjörðum þar sem fjórtán komma eitt prósent íbúa eru innflytjendur .".toLowerCase()); + "hlutfallið á Vestfjörðum þar sem fjórtán komma eitt prósent íbúa eru innflytjendur .".toLowerCase()); // both we and regina make this error with "mínútu" instead of "mínútur" testSentences.put("Hann bætti Íslandsmet sitt í 5.000 m kappakstri um 11 mín.", "Hann bætti Íslandsmet sitt í fimm þúsund metra kappakstri um ellefu mínútu .".toLowerCase());