📄 voicemanager.java
字号:
/** * Copyright 2003 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL * WARRANTIES. */package com.sun.speech.freetts;import java.io.FileNotFoundException;import java.io.IOException;import java.io.FileInputStream;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.File;import java.net.URI;import java.net.URL;import java.net.URLClassLoader;import java.net.MalformedURLException;import java.net.JarURLConnection;import java.util.jar.Attributes;import java.util.jar.Attributes.Name;import java.net.URLStreamHandlerFactory;/** * Provides access to voices for all of FreeTTS. There is only one * instance of the VoiceManager. * * Each call to getVoices() creates a new instance of each voice. * * @see Voice * @see VoiceDirectory */public class VoiceManager { private static final VoiceManager INSTANCE = new VoiceManager(); private static final String fileSeparator = System.getProperty("file.separator"); private static final String pathSeparator = System.getProperty("path.separator"); // we only want one class loader, otherwise the static information // for loaded classes would be duplicated for each class loader private static final DynamicClassLoader classLoader = new DynamicClassLoader(new URL[0]); private VoiceManager() { // do nothing } /** * Gets the instance of the VoiceManager * * @return a VoiceManager */ public static VoiceManager getInstance() { return INSTANCE; } /** * Provide an array of all voices available to FreeTTS. * * First, if the "freetts.voices" property is set, it is assumed * to be a comma-separated list of VoiceDirectory classnames * (e.g., * "-Dfreetts.voices=com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory"). * If this property exists, the VoiceManager will use only * this property to find voices -- no other method described below * will be used. The primary purpose for this property is testing * and for use with WebStart. * * <p>Second, the file internal_voices.txt is looked for in the * same directory as VoiceManager.class. If the file does not * exist, the VoiceManager moves on. Next, it looks for * voices.txt in the same directory as freetts.jar. If the file * does not exist, the VoiceManager moves on. Next, if the * property "freetts.voicesfile" is defined, then that file is * read in. If the property is defined and the file does not * exist, then an error is raised. * * <P>Every voices file that is read in contains a list of * VoiceDirectory class names. * * <p>Next, the voice manager looks for freetts voice jarfiles that * may exist in well-known locations. The directory that contains * freetts.jar is searched for voice jarfiles, then directories * specified by the "freetts.voicespath" system property. * Any jarfile whose Manifest contains * "FreeTTSVoiceDefinition: true" is assumed to be a FreeTTS * voice, and the Manifest's "Main-Class" entry is assumed to be * the name of the voice directory. The dependencies of the voice * jarfiles specified by the "Class-Path" Manifest entry are also * loaded. * * <p>The VoiceManager instantiates each voice directory * and calls getVoices() on each. * * @return the array of new instances of all available voices */ public Voice[] getVoices() { UniqueVector voices = new UniqueVector(); VoiceDirectory[] voiceDirectories = getVoiceDirectories(); for (int i = 0; i < voiceDirectories.length; i++) { voices.addArray(voiceDirectories[i].getVoices()); } Voice[] voiceArray = new Voice[voices.size()]; return (Voice[]) voices.toArray(voiceArray); } /** * Prints detailed information about all available voices. * * @return a String containing the information */ public String getVoiceInfo() { String infoString = ""; VoiceDirectory[] voiceDirectories = getVoiceDirectories(); for (int i = 0; i < voiceDirectories.length; i++) { infoString += voiceDirectories[i].toString(); } return infoString; } /** * Creates an array of all voice directories of all available * voices using the criteria specified by the contract for * getVoices(). * * @return the array of voice directories * @see getVoices() */ private VoiceDirectory[] getVoiceDirectories() { try { // If there is a freetts.voices property, it means two // things: 1) it is a comma separated list of class names // 2) no other attempts to find voices should be // made // // The main purpose for this property is to allow for // voices to be found via WebStart. // String voiceClasses = System.getProperty("freetts.voices"); if (voiceClasses != null) { return getVoiceDirectoryNamesFromProperty(voiceClasses); } // Get voice directory names from voices files UniqueVector voiceDirectoryNames = getVoiceDirectoryNamesFromFiles(); //System.out.println("TEST: got " + // voiceDirectoryNames.size() + " names from voices files"); // Get list of voice jars UniqueVector pathURLs = getVoiceJarURLs(); voiceDirectoryNames.addVector( getVoiceDirectoryNamesFromJarURLs(pathURLs)); //TEST //for (int i = 0; i < voiceDirectoryNames.size(); i++) { // System.out.println("TEST vd: " + voiceDirectoryNames.get(i)); //} // Get dependencies // Copy of vector made because vector may be modified by // each call to getDependencyURLs URL[] voiceJarURLs = (URL[]) pathURLs.toArray(new URL[pathURLs.size()]); for (int i = 0; i < voiceJarURLs.length; i++) { getDependencyURLs(voiceJarURLs[i], pathURLs); } // Extend class path for (int i = 0; i < pathURLs.size(); i++) { classLoader.addUniqueURL((URL) pathURLs.get(i)); } //TEST //System.out.println("TEST ClassLoader Path:"); //URL[] classPath = classLoader.getURLs(); //for (int i = 0; i < classPath.length; i++) { // System.out.println(classPath[i]); //} // Create an instance of each voice directory UniqueVector voiceDirectories = new UniqueVector(); for (int i = 0; i < voiceDirectoryNames.size(); i++) { //System.out.println("TEST About to try and load " + (String) // voiceDirectoryNames.get(i)); Class c = Class.forName((String) voiceDirectoryNames.get(i), true, classLoader); voiceDirectories.add(c.newInstance()); } return (VoiceDirectory[]) voiceDirectories.toArray(new VoiceDirectory[voiceDirectories.size()]); } catch (InstantiationException e) { throw new Error("Unable to load voice directory. " + e); } catch (ClassNotFoundException e) { throw new Error("Unable to load voice directory. " + e); } catch (IllegalAccessException e) { throw new Error("Unable to load voice directory. " + e); } } /** * Gets VoiceDirectory instances by parsing a comma separated * String of VoiceDirectory class names. */ private VoiceDirectory[] getVoiceDirectoryNamesFromProperty( String voiceClasses) throws InstantiationException, IllegalAccessException, ClassNotFoundException { String[] classnames = voiceClasses.split(","); VoiceDirectory[] directories = new VoiceDirectory[classnames.length]; for (int i = 0; i < directories.length; i++) { Class c = Class.forName(classnames[i]); directories[i] = (VoiceDirectory) c.newInstance(); } return directories; } /** * Recursively gets the urls of the class paths that url is * dependant on. * * Conventions specified in * http://java.sun.com/j2se/1.4.1/docs/guide/extensions/spec.html#bundled * are followed. * * @param url the url to recursively check. If it ends with a "/" * then it is presumed to be a directory, and is not checked. * Otherwise it is assumed to be a jar, and its manifest is read * to get the urls Class-Path entry. These urls are passed to * this method recursively. * * @param dependencyURLs a vector containing all of the dependant * urls found. This parameter is modified as urls are added to * it. */ private void getDependencyURLs(URL url, UniqueVector dependencyURLs) { try { String urlDirName = getURLDirName(url); if (url.getProtocol().equals("jar")) { // only check deps of jars // read in Class-Path attribute of jar Manifest JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); Attributes attributes = jarConnection.getMainAttributes(); String fullClassPath = attributes.getValue(Attributes.Name.CLASS_PATH); if (fullClassPath == null || fullClassPath.equals("")) { return; // no classpaths to add } // The URLs are separated by one or more spaces String[] classPath = fullClassPath.split("\\s+"); URL classPathURL; for (int i = 0; i < classPath.length; i++) { try { if (classPath[i].endsWith("/")) { // assume directory classPathURL = new URL("file:" + urlDirName + classPath[i]); } else { // assume jar classPathURL = new URL("jar", "", "file:" + urlDirName + classPath[i] + "!/"); } } catch (MalformedURLException e) { System.err.println( "Warning: unable to resolve dependency " + classPath[i] + " referenced by " + url); continue; } //System.out.println("TEST: adding dep url: " + classPathURL); // don't get in a recursive loop if two jars // are mutually dependant if (!dependencyURLs.contains(classPathURL)) { dependencyURLs.add(classPathURL); getDependencyURLs(classPathURL, dependencyURLs); } } } } catch (IOException e) { e.printStackTrace(); } } /** * Gets the names of the subclasses of VoiceDirectory that are * listed in the voices.txt files. * * @return a vector containing the String names of the voice * directories */ private UniqueVector getVoiceDirectoryNamesFromFiles() { try { UniqueVector voiceDirectoryNames = new UniqueVector(); // first, load internal_voices.txt InputStream is = this.getClass().getResourceAsStream("internal_voices.txt"); if (is != null) { // if it doesn't exist, move on voiceDirectoryNames.addVector( getVoiceDirectoryNamesFromInputStream(is)); } // next, try loading voices.txt try { voiceDirectoryNames.addVector( getVoiceDirectoryNamesFromFile(getBaseDirectory() + "voices.txt")); } catch (FileNotFoundException e) { // do nothing } catch (IOException e) { // do nothing } // last, read voices from property freetts.voicesfile String voicesFile = System.getProperty("freetts.voicesfile"); if (voicesFile != null) { voiceDirectoryNames.addVector( getVoiceDirectoryNamesFromFile(voicesFile)); } return voiceDirectoryNames; } catch (IOException e) { throw new Error("Error reading voices files. " + e); } } /** * Gets the voice directory class names from a list of urls * specifying voice jarfiles. The class name is specified as the * Main-Class in the manifest of the jarfiles. * * @param urls a UniqueVector of URLs that refer to the voice jarfiles * * @return a UniqueVector of Strings representing the voice directory * class names */ private UniqueVector getVoiceDirectoryNamesFromJarURLs(UniqueVector urls) { try { UniqueVector voiceDirectoryNames = new UniqueVector(); for (int i = 0; i < urls.size(); i++) { //System.out.println("TEST: reading manifest of " + // (URL)urls.get(i)); JarURLConnection jarConnection = (JarURLConnection) ((URL) urls.get(i)).openConnection(); Attributes attributes = jarConnection.getMainAttributes(); String mainClass = attributes.getValue(Attributes.Name.MAIN_CLASS); //System.out.println("TEST: Main-Class: " + mainClass); if (mainClass == null || mainClass.trim().equals("")) { throw new Error("No Main-Class found in jar " + (URL)urls.get(i)); } voiceDirectoryNames.add(mainClass); } return voiceDirectoryNames; } catch (IOException e) { throw new Error("Error reading jarfile manifests. "); } } /** * Gets the list of voice jarfiles. Voice jarfiles are searched * for in the same directory as freetts.jar and the directories * specified by the freetts.voicespath system property. Voice * jarfiles are defined by the manifest entry * "FreeTTSVoiceDefinition: true" * * @return a vector of URLs refering to the voice jarfiles. */ private UniqueVector getVoiceJarURLs() { UniqueVector voiceJarURLs = new UniqueVector(); // check in same directory as freetts.jar try { String baseDirectory = getBaseDirectory(); if (!baseDirectory.equals("")) { // not called from a jar voiceJarURLs.addVector(getVoiceJarURLsFromDir(baseDirectory)); } } catch (FileNotFoundException e) { // do nothing } // search voicespath String voicesPath = System.getProperty("freetts.voicespath", ""); if (!voicesPath.equals("")) { String[] dirNames = voicesPath.split(pathSeparator); for (int i = 0; i < dirNames.length; i++) { try { //System.out.println("TEST: adding voicepath " + dirNames[i]); voiceJarURLs.addVector(getVoiceJarURLsFromDir(dirNames[i])); } catch (FileNotFoundException e) { throw new Error("Error loading jars from voicespath " + dirNames[i] + ". "); } } } return voiceJarURLs; } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -