/** * Copyright 2000-2009 DFKI GmbH. * All Rights Reserved. Use is subject to license terms. * * This file is part of MARY TTS. * * MARY TTS 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, version 3 of the License. * * 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. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package marytts.tools.transcription; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import javax.swing.BoxLayout; import javax.swing.CellEditor; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.CellEditorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; import marytts.cart.CART; import marytts.exceptions.MaryConfigurationException; import marytts.modules.phonemiser.AllophoneSet; import marytts.modules.phonemiser.TrainedLTS; import marytts.tools.newlanguage.LTSTrainer; /** * * TranscriptionTable, A Table panel, tracs events in user transcription entries * * @author sathish pammi * */ public class TranscriptionTable extends JPanel implements ActionListener { private JTable table; int itsRow = 0; int rowEnterPressed = -1; TranscriptionTableModel transcriptionModel; private AllophoneSet phoneSet; private int editableColumns = 2; int previousRow = 0; boolean trainPredict = false; protected boolean removeTrailingOneFromPhones = true; JScrollPane scrollpane; String locale; CellEditorListener editorListener = null; public TranscriptionTable() throws Exception { super(); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); transcriptionModel = new TranscriptionTableModel(); table = new JTable(transcriptionModel); table.setPreferredScrollableViewportSize(new Dimension(500, 70)); // table.setFillsViewportHeight(true); table.getSelectionModel().addListSelectionListener(new RowListener()); table.getColumnModel().getColumn(0).setCellRenderer(new CustomTableCellRenderer()); table.getColumnModel().getColumn(2).setCellRenderer(new CustomTableCellRenderer()); table.addKeyListener(new KeyEventListener()); table.setFont(new Font("Serif", Font.TRUETYPE_FONT, 12)); scrollpane = new JScrollPane(table); add(scrollpane); TableColumn column = table.getColumnModel().getColumn(1); int columnSize = column.getPreferredWidth(); column.setPreferredWidth(2 * columnSize); table.getColumnModel().getColumn(2).setPreferredWidth(2 * columnSize); table.setSurrendersFocusOnKeystroke(true); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); } public void actionPerformed(ActionEvent event) { String command = event.getActionCommand(); } 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); } } } /** * verify transcription syntax * * @param row * row */ private void checkTranscriptionSyntax(int row) { String transcription = (String) transcriptionModel.getDataAt(row, 2); 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); } } public boolean isDataModified() { return this.transcriptionModel.isDataModified(); } 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("alignment ... "); // make some alignment iterations for (int i = 0; i < 5; i++) { System.out.println("iteration " + i); tp.alignIteration(); } System.out.println("alignment completed."); System.out.println("training ... "); CART st = tp.trainTree(100); tp.save(st, treeAbsolutePath); System.out.println("training completed."); return tp; } /** * train and predict module * * @param treeAbsolutePath * treeAbsolutePath * @param myRemoveTrailingOneFromPhones * myRemoveTrailingOneFromPhones * @throws MaryConfigurationException * MaryConfigurationException */ public void trainPredict(String treeAbsolutePath, boolean myRemoveTrailingOneFromPhones) throws MaryConfigurationException { Object[][] tableData = transcriptionModel.getData(); boolean[] hasManualVerify = transcriptionModel.getManualVerifiedList(); boolean[] hasCorrectSyntax = transcriptionModel.getCorrectSyntaxList(); this.removeTrailingOneFromPhones = myRemoveTrailingOneFromPhones; // 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; } try { LTSTrainer tp = this.trainLTS(treeAbsolutePath); FileInputStream fis = new FileInputStream(treeAbsolutePath); TrainedLTS trainedLTS = new TrainedLTS(phoneSet, fis, this.removeTrailingOneFromPhones); fis.close(); 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); } } if (((String) transcriptionModel.getDataAt(itsRow, 2)).equals("")) { String grapheme = (String) tableData[itsRow][1]; String phone = trainedLTS.syllabify(trainedLTS.predictPronunciation(grapheme)); transcriptionModel.setValueAt(phone.replaceAll("\\s+", ""), itsRow, 2); transcriptionModel.setAsCorrectSyntax(itsRow, true); transcriptionModel.setAsManualVerify(itsRow, false); } } catch (IOException e) { throw new MaryConfigurationException("Problem training/predicting", e); } trainPredict = true; } /** * save transcription into file * * @param fileName * fileName */ public void saveTranscription(String fileName) { try { 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; suffix = ""; } else { baseName = filename.substring(0, filename.lastIndexOf(".")); suffix = filename.substring(filename.lastIndexOf("."), filename.length()); } 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); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Load transcription from file * * @param fileName * fileName */ public void loadTranscription(String fileName) { try { this.transcriptionModel.loadTranscription(fileName, false); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } checkTranscription(); scrollpane.updateUI(); table.repaint(); this.repaint(); this.updateUI(); } /** * Add words from file * * @param fileName * fileName */ public void addWordsToTranscription(String fileName) { try { this.transcriptionModel.loadTranscription(fileName, true); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } checkTranscription(); scrollpane.updateUI(); table.repaint(); this.repaint(); this.updateUI(); } /** * Load transcription from a hashmap * * @param map * map * @throws Exception * Exception */ @Deprecated // doesn't seem to get used -- remove? public void loadTranscription(HashMap<String, Integer> map) throws Exception { this.transcriptionModel.loadTranscription(map); checkTranscription(); scrollpane.updateUI(); table.repaint(); this.repaint(); this.updateUI(); } /** * Load transcription from a arrayList * * @param arrList * arrList * @throws Exception * Exception */ public void loadTranscription(ArrayList<String> arrList) throws Exception { this.transcriptionModel.loadTranscription(arrList); checkTranscription(); scrollpane.updateUI(); table.repaint(); this.repaint(); this.updateUI(); } /** * load phoneset * * @param filePath * filePath */ public void loadPhoneSet(String filePath) { try { phoneSet = AllophoneSet.getAllophoneSet(filePath); locale = phoneSet.getLocale().toString(); } catch (MaryConfigurationException e) { e.printStackTrace(); } } public String getLocaleString() { return locale; } /** * Row event listener * * @author sathish * */ private class RowListener implements ListSelectionListener { public void valueChanged(ListSelectionEvent event) { if (event.getValueIsAdjusting()) { return; } itsRow = table.getSelectionModel().getLeadSelectionIndex(); table.repaint(); checkTranscription(); } } /** * Column event listener * * @author sathish * */ private class ColumnListener implements ListSelectionListener { public void valueChanged(ListSelectionEvent event) { if (event.getValueIsAdjusting()) { return; } itsRow = table.getSelectionModel().getLeadSelectionIndex(); table.repaint(); } } /** * Key event listener * * @author sathish * */ private class KeyEventListener implements KeyListener { public void keyPressed(KeyEvent arg0) { if (arg0.getKeyCode() == 10) { // enter key rowEnterPressed = itsRow; } } public void keyReleased(KeyEvent arg0) { System.out.println("Received key release event, key nr. " + arg0.getKeyCode()); System.out.println("Key released in row " + itsRow); if (arg0.getKeyCode() == 10) { // enter key if (rowEnterPressed != -1) { // enter was pressed in a row in non-editing mode; edit this row System.out.println("RowEnterPressed = " + rowEnterPressed); table.getSelectionModel().setLeadSelectionIndex(rowEnterPressed); table.editCellAt(rowEnterPressed, 2); } else { // coming out of edit, start editing next line System.out.println("row nr. " + itsRow); // table.changeSelection(itsRow, 2, false, false); int nextRow = itsRow + 1; table.getSelectionModel().setLeadSelectionIndex(nextRow); table.editCellAt(nextRow, 2); } if (editorListener == null) { CellEditor editor = table.getCellEditor(); editorListener = new CellEditListener(); editor.addCellEditorListener(editorListener); } } int[] selectedRows = table.getSelectedRows(); if (arg0.getKeyCode() == 32) { for (int i = 0; i < selectedRows.length; i++) { if ((Boolean) transcriptionModel.getValueAt(selectedRows[i], 3)) { transcriptionModel.setValueAt((Object) (false), selectedRows[i], 3); } else { transcriptionModel.setValueAt((Object) (true), selectedRows[i], 3); } } } } public void keyTyped(KeyEvent arg0) { } } private class CellEditListener implements CellEditorListener { public void editingCanceled(ChangeEvent e) { System.out.println("cancelled"); rowEnterPressed = -1; } public void editingStopped(ChangeEvent e) { System.out.println("stopped: " + itsRow); checkTranscriptionSyntax(itsRow); transcriptionModel.setAsManualVerify(itsRow, true); rowEnterPressed = -1; } } /** * Color rendering class * * @author sathish * */ public class CustomTableCellRenderer extends DefaultTableCellRenderer { public Component getTableCellRendererComponent(JTable ttable, Object obj, boolean isSelected, boolean hasFocus, int row, int column) { Component cell = super.getTableCellRendererComponent(ttable, obj, isSelected, hasFocus, row, column); boolean[] hasManualVerify = transcriptionModel.getManualVerifiedList(); boolean[] hasCorrectSyntax = transcriptionModel.getCorrectSyntaxList(); if (column == 0) { cell.setFont(new Font("Serif", Font.TRUETYPE_FONT, 12)); } if (column == 2) { cell.setFont(new Font("Serif", Font.BOLD, 12)); if (!hasCorrectSyntax[row]) { cell.setForeground(Color.RED); transcriptionModel.setAsManualVerify(row, false); } else if (!hasManualVerify[row]) { cell.setForeground(Color.LIGHT_GRAY); } else { cell.setForeground(Color.BLACK); } } else { cell.setForeground(Color.BLACK); } return cell; } } public void changeTableFont(String fontName) { int fontSize = table.getFont().getSize(); System.out.println("prev: " + table.getFont().getName()); table.setFont(new Font(fontName, Font.TRUETYPE_FONT, fontSize)); System.out.println("next: " + fontName); } }