package marytts.tools.transcription; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import javax.xml.parsers.ParserConfigurationException; import marytts.cart.CART; import marytts.cart.StringPredictionTree; import marytts.exceptions.MaryConfigurationException; import marytts.features.FeatureDefinition; import marytts.fst.AlignerTrainer; import marytts.fst.StringPair; import marytts.modules.phonemiser.AllophoneSet; import marytts.modules.phonemiser.TrainedLTS; import marytts.tools.dbselection.DBHandler; import marytts.tools.newlanguage.LTSTrainer; import marytts.tools.newlanguage.en_US.CMUDict2MaryFST; import marytts.tools.transcription.TranscriptionTableModel; import marytts.util.io.FileUtils; /** * * LTSLexiconPOSBuilder has the same functionalities of TRANSCRIPTION TOOL but without GUI (better for a remote use for large * lexicon and for scripting). This class is a light version of TranscriptionTable * * Train Letter-to-sound(LTS) rules, create FST dictionary and POS tagger * * @author Fabio Tesser <fabio.tesser@gmail.com> * * Example use: * <code>java -showversion -ea -Xmx4096m -cp "$MARY_BASE/lib/*" marytts.tools.transcription.LTSLexiconPOSBuilder ./marytts-lang-it/src/main/resources/marytts/language/it/lexicon/allophones.it.xml ./marytts-lang-it/lib/modules/it/lexicon/it.txt </code> * * */ public class LTSLexiconPOSBuilder { TranscriptionTableModel transcriptionModel; protected boolean removeTrailingOneFromPhones = true; private AllophoneSet phoneSet; String locale; public LTSLexiconPOSBuilder(String phoneSetFileName, String transcriptionFileName, boolean removeTrailingOneFromPhones) throws Exception { loadPhoneSet(phoneSetFileName); transcriptionModel = new TranscriptionTableModel(); loadTranscription(transcriptionFileName); this.removeTrailingOneFromPhones = removeTrailingOneFromPhones; } public LTSLexiconPOSBuilder(String phoneSetFileName, String transcriptionFileName) throws Exception { this(phoneSetFileName, transcriptionFileName, true); } /** * load phoneset * * @param filePath * filePath * @throws MaryConfigurationException * MaryConfigurationException */ private void loadPhoneSet(String filePath) throws MaryConfigurationException { phoneSet = AllophoneSet.getAllophoneSet(filePath); locale = phoneSet.getLocale().toString(); } /** * Load transcription from file * * @param fileName * fileName * @throws Exception * Exception */ private void loadTranscription(String fileName) throws Exception { transcriptionModel.loadTranscription(fileName, false); checkTranscription(); } private void checkTranscription() { int size = transcriptionModel.getData().length; for (int row = 0; row < size; row++) { String transcription = (String) transcriptionModel.getDataAt(row, 2); if (transcription == null) continue; if (transcription.matches("\\s+")) { transcription = transcription.replaceAll("\\s+", ""); this.transcriptionModel.setValueAt(transcription, row, 2); } if (!transcription.equals("")) { boolean ok = phoneSet.checkAllophoneSyntax(transcription); transcriptionModel.setAsCorrectSyntax(row, ok); } else { transcriptionModel.setAsCorrectSyntax(row, false); } } } /** * train and predict module * * @param treeAbsolutePath * treeAbsolutePath * @throws IOException * IOException * @throws MaryConfigurationException * MaryConfigurationException */ public void trainPredict(String treeAbsolutePath) throws IOException, MaryConfigurationException { Object[][] tableData = transcriptionModel.getData(); boolean[] hasManualVerify = transcriptionModel.getManualVerifiedList(); boolean[] hasCorrectSyntax = transcriptionModel.getCorrectSyntaxList(); // Check for number of manual entries available int numberOfManualEntries = 0; for (int i = 0; i < hasManualVerify.length; i++) { if (hasManualVerify[i]) numberOfManualEntries++; } if (numberOfManualEntries == 0) { System.out.println("No manual entries available for train and predict ... do nothing!"); return; } trainLTS(treeAbsolutePath); FileInputStream fis = new FileInputStream(treeAbsolutePath); TrainedLTS trainedLTS = new TrainedLTS(phoneSet, fis, this.removeTrailingOneFromPhones); for (int i = 0; i < tableData.length; i++) { if (!(hasManualVerify[i] && hasCorrectSyntax[i])) { String grapheme = (String) tableData[i][1]; if (grapheme == null) continue; String phone = trainedLTS.syllabify(trainedLTS.predictPronunciation(grapheme)); transcriptionModel.setValueAt(phone.replaceAll("\\s+", ""), i, 2); transcriptionModel.setAsCorrectSyntax(i, true); transcriptionModel.setAsManualVerify(i, false); } } } private LTSTrainer trainLTS(String treeAbsolutePath) throws IOException { Object[][] tableData = transcriptionModel.getData(); HashMap<String, String> map = new HashMap<String, String>(); boolean[] hasManualVerify = transcriptionModel.getManualVerifiedList(); boolean[] hasCorrectSyntax = transcriptionModel.getCorrectSyntaxList(); for (int i = 0; i < tableData.length; i++) { if (hasManualVerify[i] && hasCorrectSyntax[i]) { String grapheme = (String) tableData[i][1]; String phone = (String) tableData[i][2]; if (!phone.equals("")) { map.put(grapheme, phone); transcriptionModel.setAsCorrectSyntax(i, true); } } } LTSTrainer tp = new LTSTrainer(phoneSet, true, true, 2); tp.readLexicon(map); System.out.println("training ... "); // make some alignment iterations for (int i = 0; i < 5; i++) { System.out.println("iteration " + i); tp.alignIteration(); } System.out.println("training completed."); CART st = tp.trainTree(100); tp.save(st, treeAbsolutePath); return tp; } private String getLocaleString() { return locale; } /** * save transcription into file * * @param fileName * fileName * @throws Exception * Exception */ public void saveTranscription(String fileName) throws Exception { this.transcriptionModel.saveTranscription(fileName); // File parentDir = (new File(fileName)).getParentFile(); // String parentPath = parentDir.getAbsolutePath(); File saveFile = new File(fileName); String dirName = saveFile.getParentFile().getAbsolutePath(); String filename = saveFile.getName(); String baseName, suffix; if (filename.lastIndexOf(".") == -1) { baseName = filename; } else { baseName = filename.substring(0, filename.lastIndexOf(".")); } String lexiconFile = dirName + File.separator + baseName + "_lexicon.dict"; String fstFile = dirName + File.separator + baseName + "_lexicon.fst"; String posFile = dirName + File.separator + baseName + "_pos.list"; String posFst = dirName + File.separator + baseName + "_pos.fst"; transcriptionModel.saveSampaLexiconFormat(lexiconFile, phoneSet); transcriptionModel.createLexicon(lexiconFile, fstFile); transcriptionModel.saveFunctionalWords(posFile); transcriptionModel.createPOSFst(posFile, posFst); // trainLTS(treeAbsolutePath); } /** * @param args * first argument, PhoneSet file name; second argument, Transcriptions file name * @throws Exception * Exception */ public static void main(String[] args) throws Exception { try { // Get filenames from args String phoneSetFileName = args[0]; String transcriptionsFileName = args[1]; boolean myRemoveTrailingOneFromPhones = true; if (args.length > 2) { myRemoveTrailingOneFromPhones = Boolean.getBoolean(args[2]); } // Create object from files LTSLexiconPOSBuilder myLTSLexiconPOSBuilder = new LTSLexiconPOSBuilder(phoneSetFileName, transcriptionsFileName, myRemoveTrailingOneFromPhones); // Splitting of dirName baseName suffix String dirName = null; String baseName = null; String suffix = null; File transcriptionFile = new File(transcriptionsFileName); dirName = transcriptionFile.getParentFile().getAbsolutePath(); String filename = transcriptionFile.getName(); if (filename.lastIndexOf(".") == -1) { baseName = filename; } else { baseName = filename.substring(0, filename.lastIndexOf(".")); } String treeAbsolutePath = dirName + File.separator + baseName + ".lts"; String lexout = dirName + File.separator + baseName + ".lextxt"; // Procedure System.out.println("trainPredict ..."); myLTSLexiconPOSBuilder.trainPredict(treeAbsolutePath); System.out.println("... done."); System.out.println("saveTranscription ..."); myLTSLexiconPOSBuilder.saveTranscription(lexout); System.out.println("... done."); } catch (Exception e) { System.out.println("Problem processing the following input:"); System.out.println("args[0]:" + args[0]); System.out.println("args[1]:" + args[1]); System.out.println("\n"); e.printStackTrace(); System.out.println(""); System.out.println("Failure exit"); System.exit(-1); } } }