/** * Constructor providing the individual filenames of files that are required. * * @param allophonesFilename * @param userdictFilename * @param lexiconFilename * @param ltsFilename * @param removetrailingonefromphonesBoolean * @throws Exception */ public JPhonemiser( String componentName, MaryDataType inputType, MaryDataType outputType, String allophonesProperty, String userdictProperty, String lexiconProperty, String ltsProperty, String removetrailingonefromphonesProperty) throws IOException, MaryConfigurationException { super( componentName, inputType, outputType, MaryRuntimeUtils.needAllophoneSet(allophonesProperty).getLocale()); allophoneSet = MaryRuntimeUtils.needAllophoneSet(allophonesProperty); // userdict is optional String userdictFilename = MaryProperties.getFilename(userdictProperty); // may be null if (userdictFilename != null) { if (new File(userdictFilename).exists()) { userdict = readLexicon(userdictFilename); } else { logger.info( "User dictionary '" + userdictFilename + "' for locale '" + getLocale() + "' does not exist. Ignoring."); } } // HB 150915 Need to allow lexiconProperty to be a list. If lexicon is *fst, load as before, if // *dict, load like userlex // Lookup in the order of the lexiconProperty // First: keep lexicon the way it is, and add no.secondary_lexicon to no.config System.err.println("lexiconProperty: " + MaryProperties.getProperty(lexiconProperty)); String secondary_lexiconFilename = MaryProperties.getProperty("da.secondary_lexicon"); if (secondary_lexiconFilename != null) { System.err.println("Loading da.secondary_lexicon: " + secondary_lexiconFilename); secondary_lexicon = readLexiconStream( secondary_lexiconFilename, MaryProperties.needStream("da.secondary_lexicon")); } InputStream lexiconStream = MaryProperties.needStream(lexiconProperty); lexicon = new FSTLookup(lexiconStream, lexiconProperty); InputStream ltsStream = MaryProperties.needStream(ltsProperty); if (removetrailingonefromphonesProperty != null) { this.removeTrailingOneFromPhones = MaryProperties.getBoolean(removetrailingonefromphonesProperty, true); } lts = new TrainedLTS(allophoneSet, ltsStream, this.removeTrailingOneFromPhones); }
/** * Instantiate an object by calling one of its constructors. * * @param objectInitInfo a string description of the object to instantiate. The objectInitInfo is * expected to have one of the following forms: * <ol> * <li>my.cool.Stuff * <li>my.cool.Stuff(any,string,args,without,spaces) * <li>my.cool.Stuff(arguments,$my.special.property,other,args) * </ol> * where 'my.special.property' is a property in one of the MARY config files. * @return the newly instantiated object. * @throws ClassNotFoundException * @throws IllegalArgumentException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException * @throws SecurityException * @throws NoSuchMethodException */ public static Object instantiateObject(String objectInitInfo) throws MaryConfigurationException { Object obj = null; String[] args = null; String className = null; try { if (objectInitInfo.contains("(")) { // arguments int firstOpenBracket = objectInitInfo.indexOf('('); className = objectInitInfo.substring(0, firstOpenBracket); int lastCloseBracket = objectInitInfo.lastIndexOf(')'); args = objectInitInfo.substring(firstOpenBracket + 1, lastCloseBracket).split(","); for (int i = 0; i < args.length; i++) { if (args[i].startsWith("$")) { // replace value with content of property named after the $ args[i] = MaryProperties.getProperty(args[i].substring(1)); } args[i] = args[i].trim(); } } else { // no arguments className = objectInitInfo; } Class<? extends Object> theClass = Class.forName(className).asSubclass(Object.class); // Now invoke Constructor with args.length String arguments if (args != null) { Class<String>[] constructorArgTypes = new Class[args.length]; Object[] constructorArgs = new Object[args.length]; for (int i = 0; i < args.length; i++) { constructorArgTypes[i] = String.class; constructorArgs[i] = args[i]; } Constructor<? extends Object> constructor = (Constructor<? extends Object>) theClass.getConstructor(constructorArgTypes); obj = constructor.newInstance(constructorArgs); } else { obj = theClass.newInstance(); } } catch (Exception e) { // try to make e's message more informative if possible throw new MaryConfigurationException( "Cannot instantiate object from '" + objectInitInfo + "': " + MaryUtils.getFirstMeaningfulMessage(e), e); } return obj; }
/** * Convenience method to access the allophone set referenced in the MARY property with the given * name. * * @param propertyName name of the property referring to the allophone set * @throws MaryConfigurationException if the allophone set cannot be obtained * @return the requested allophone set. This method will never return null; if it cannot get the * allophone set, it throws an exception. */ public static AllophoneSet needAllophoneSet(String propertyName) throws MaryConfigurationException { String propertyValue = MaryProperties.getProperty(propertyName); if (propertyValue == null) { throw new MaryConfigurationException("No such property: " + propertyName); } if (AllophoneSet.hasAllophoneSet(propertyValue)) { return AllophoneSet.getAllophoneSetById(propertyValue); } InputStream alloStream; try { alloStream = MaryProperties.needStream(propertyName); } catch (FileNotFoundException e) { throw new MaryConfigurationException( "Cannot open allophone stream for property " + propertyName, e); } assert alloStream != null; return AllophoneSet.getAllophoneSet(alloStream, propertyValue); }
/** * Compile a regex pattern used to determine whether tokens are processed as punctuation or not, * based on whether their <code>pos</code> attribute matches the pattern. * * @author ingmar */ protected void setPunctuationPosRegex() { String language = getLocale().getLanguage(); String propertyName = language + ".pos.punct.regex"; String defaultRegex = "\\$PUNCT"; String regex = MaryProperties.getProperty(propertyName); if (regex == null) { logger.debug(String.format("Property %s not set, using default", propertyName)); regex = defaultRegex; } else { logger.debug(String.format("Using property %s", propertyName)); } try { punctuationPosRegex = Pattern.compile(regex); } catch (PatternSyntaxException e) { logger.error( String.format("Could not compile regex pattern /%s/, using default instead", regex)); punctuationPosRegex = Pattern.compile(defaultRegex); } logger.debug(String.format("Punctuation regex pattern set to /%s/", punctuationPosRegex)); return; }
/** * Instantiate an object by calling one of its constructors. * * @param objectInitInfo a string description of the object to instantiate. The objectInitInfo is * expected to have one of the following forms: * <ol> * <li>my.cool.Stuff * <li>my.cool.Stuff(any,string,args,without,spaces) * <li>my.cool.Stuff(arguments,$my.special.property,other,args) * </ol> * where 'my.special.property' is a property in one of the MARY config files. * @return the newly instantiated object. * @throws ClassNotFoundException * @throws IllegalArgumentException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException * @throws SecurityException * @throws NoSuchMethodException */ public static Object instantiateObject(String objectInitInfo) throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { Object obj = null; String[] args = null; String className = null; if (objectInitInfo.contains("(")) { // arguments int firstOpenBracket = objectInitInfo.indexOf('('); className = objectInitInfo.substring(0, firstOpenBracket); int lastCloseBracket = objectInitInfo.lastIndexOf(')'); args = objectInitInfo.substring(firstOpenBracket + 1, lastCloseBracket).split(","); for (int i = 0; i < args.length; i++) { if (args[i].startsWith("$")) { // replace value with content of property named after the $ args[i] = MaryProperties.getProperty(args[i].substring(1)); } args[i] = args[i].trim(); } } else { // no arguments className = objectInitInfo; } Class<? extends Object> theClass = Class.forName(className).asSubclass(Object.class); // Now invoke Constructor with args.length String arguments if (args != null) { Class<String>[] constructorArgTypes = new Class[args.length]; Object[] constructorArgs = new Object[args.length]; for (int i = 0; i < args.length; i++) { constructorArgTypes[i] = String.class; constructorArgs[i] = args[i]; } Constructor<? extends Object> constructor = (Constructor<? extends Object>) theClass.getConstructor(constructorArgTypes); obj = constructor.newInstance(constructorArgs); } else { obj = theClass.newInstance(); } return obj; }
/** @author marc */ public class MaryRuntimeUtils { public static void ensureMaryStarted() throws Exception { synchronized (MaryConfig.getMainConfig()) { if (Mary.currentState() == Mary.STATE_OFF) { Mary.startup(); } } } /** * Instantiate an object by calling one of its constructors. * * @param objectInitInfo a string description of the object to instantiate. The objectInitInfo is * expected to have one of the following forms: * <ol> * <li>my.cool.Stuff * <li>my.cool.Stuff(any,string,args,without,spaces) * <li>my.cool.Stuff(arguments,$my.special.property,other,args) * </ol> * where 'my.special.property' is a property in one of the MARY config files. * @return the newly instantiated object. * @throws ClassNotFoundException * @throws IllegalArgumentException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException * @throws SecurityException * @throws NoSuchMethodException */ public static Object instantiateObject(String objectInitInfo) throws MaryConfigurationException { Object obj = null; String[] args = null; String className = null; try { if (objectInitInfo.contains("(")) { // arguments int firstOpenBracket = objectInitInfo.indexOf('('); className = objectInitInfo.substring(0, firstOpenBracket); int lastCloseBracket = objectInitInfo.lastIndexOf(')'); args = objectInitInfo.substring(firstOpenBracket + 1, lastCloseBracket).split(","); for (int i = 0; i < args.length; i++) { if (args[i].startsWith("$")) { // replace value with content of property named after the $ args[i] = MaryProperties.getProperty(args[i].substring(1)); } args[i] = args[i].trim(); } } else { // no arguments className = objectInitInfo; } Class<? extends Object> theClass = Class.forName(className).asSubclass(Object.class); // Now invoke Constructor with args.length String arguments if (args != null) { Class<String>[] constructorArgTypes = new Class[args.length]; Object[] constructorArgs = new Object[args.length]; for (int i = 0; i < args.length; i++) { constructorArgTypes[i] = String.class; constructorArgs[i] = args[i]; } Constructor<? extends Object> constructor = (Constructor<? extends Object>) theClass.getConstructor(constructorArgTypes); obj = constructor.newInstance(constructorArgs); } else { obj = theClass.newInstance(); } } catch (Exception e) { // try to make e's message more informative if possible throw new MaryConfigurationException( "Cannot instantiate object from '" + objectInitInfo + "': " + MaryUtils.getFirstMeaningfulMessage(e), e); } return obj; } /** * Verify if the java virtual machine is in a low memory condition. The memory is considered low * if less than a specified value is still available for processing. "Available" memory is * calculated using <code>availableMemory()</code>.The threshold value can be specified as the * Mary property mary.lowmemory (in bytes). It defaults to 20000000 bytes. * * @return a boolean indicating whether or not the system is in low memory condition. */ public static boolean lowMemoryCondition() { return MaryUtils.availableMemory() < lowMemoryThreshold(); } /** * Verify if the java virtual machine is in a very low memory condition. The memory is considered * very low if less than half a specified value is still available for processing. "Available" * memory is calculated using <code>availableMemory()</code>.The threshold value can be specified * as the Mary property mary.lowmemory (in bytes). It defaults to 20000000 bytes. * * @return a boolean indicating whether or not the system is in very low memory condition. */ public static boolean veryLowMemoryCondition() { return MaryUtils.availableMemory() < lowMemoryThreshold() / 2; } private static long lowMemoryThreshold() { if (lowMemoryThreshold < 0) // not yet initialised lowMemoryThreshold = (long) MaryProperties.getInteger("mary.lowmemory", 10000000); return lowMemoryThreshold; } private static long lowMemoryThreshold = -1; /** * List the available audio file format types, as a multi-line string. Each line consists of the * name of an Audio file format type, followed by a suffix "_FILE" if the format can be produced * as a file, and "_STREAM" if the format can be streamed. * * @return a multi-line string, or an empty string if no audio file types are available. */ public static String getAudioFileFormatTypes() { StringBuilder output = new StringBuilder(); AudioFileFormat.Type[] audioTypes = AudioSystem.getAudioFileTypes(); for (int t = 0; t < audioTypes.length; t++) { AudioFileFormat.Type audioType = audioTypes[t]; String typeName = audioType.toString(); boolean isSupported = true; if (typeName.equals("MP3")) isSupported = canCreateMP3(); else if (typeName.equals("Vorbis")) isSupported = canCreateOgg(); audioType = MaryAudioUtils.getAudioFileFormatType(typeName); if (audioType == null) { isSupported = false; } if (isSupported && AudioSystem.isFileTypeSupported(audioType)) { output.append(typeName).append("_FILE\n"); if (typeName.equals("MP3") || typeName.equals("Vorbis")) output.append(typeName).append("_STREAM\n"); } } return output.toString(); } /** Determine whether conversion to mp3 is possible. */ public static boolean canCreateMP3() { return AudioSystem.isConversionSupported(getMP3AudioFormat(), Voice.AF22050); } public static AudioFormat getMP3AudioFormat() { return new AudioFormat( new AudioFormat.Encoding("MPEG1L3"), AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, 1, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, false); // endianness doesn't matter } /** Determine whether conversion to ogg vorbis format is possible. */ public static boolean canCreateOgg() { return AudioSystem.isConversionSupported(getOggAudioFormat(), Voice.AF22050); } public static AudioFormat getOggAudioFormat() { return new AudioFormat( new AudioFormat.Encoding("VORBIS"), AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, 1, AudioSystem.NOT_SPECIFIED, AudioSystem.NOT_SPECIFIED, false); } /** * For an element in a MaryXML document, do what you can to determine the appropriate * AllophoneSet. First search for the suitable voice, then if that fails, go by locale. * * @param e * @return an allophone set if there is any way of determining it, or null. * @throws MaryConfigurationException if a suitable allophone set exists in principle, but there * were problems loading it. */ public static AllophoneSet determineAllophoneSet(Element e) throws MaryConfigurationException { AllophoneSet allophoneSet = null; Element voice = (Element) MaryDomUtils.getAncestor(e, MaryXML.VOICE); Voice maryVoice = Voice.getVoice(voice); if (maryVoice == null) { // Determine Locale in order to use default voice Locale locale = MaryUtils.string2locale( e.getOwnerDocument().getDocumentElement().getAttribute("xml:lang")); maryVoice = Voice.getDefaultVoice(locale); } if (maryVoice != null) { allophoneSet = maryVoice.getAllophoneSet(); } else { Locale locale = MaryUtils.string2locale( e.getOwnerDocument().getDocumentElement().getAttribute("xml:lang")); allophoneSet = determineAllophoneSet(locale); } return allophoneSet; } /** * Try to determine the Allophone set to use for the given locale. * * @param allophoneSet * @param locale * @return the allophone set defined for the given locale, or null if no such allophone set can be * determined. * @throws MaryConfigurationException if an allophone set exists for the given locale in * principle, but there were problems loading it. */ public static AllophoneSet determineAllophoneSet(Locale locale) throws MaryConfigurationException { AllophoneSet allophoneSet = null; String propertyPrefix = MaryProperties.localePrefix(locale); if (propertyPrefix != null) { String propertyName = propertyPrefix + ".allophoneset"; allophoneSet = needAllophoneSet(propertyName); } return allophoneSet; } /** The mary property setting determining where to save audio data. */ private static final String audiostoreProperty = MaryProperties.getProperty("synthesis.audiostore", "ram"); /** * Create an AudioDestination to which the audio data can be written. Depending on the mary * property "synthesis.audiostore", this will use either a ByteArrayOutputStream or a * FileOutputStream. The calling code is responsible for administering this AudioDestination. * * @throws IOException if the underlying OutputStream could not be created. */ public static AudioDestination createAudioDestination() throws IOException { boolean ram = false; if (audiostoreProperty.equals("ram")) ram = true; else if (audiostoreProperty.equals("file")) ram = false; else // auto if (lowMemoryCondition()) ram = false; else ram = true; return new AudioDestination(ram); } /** * Convenience method to access the allophone set referenced in the MARY property with the given * name. * * @param propertyName name of the property referring to the allophone set * @throws MaryConfigurationException if the allophone set cannot be obtained * @return the requested allophone set. This method will never return null; if it cannot get the * allophone set, it throws an exception. */ public static AllophoneSet needAllophoneSet(String propertyName) throws MaryConfigurationException { String propertyValue = MaryProperties.getProperty(propertyName); if (propertyValue == null) { throw new MaryConfigurationException("No such property: " + propertyName); } if (AllophoneSet.hasAllophoneSet(propertyValue)) { return AllophoneSet.getAllophoneSetById(propertyValue); } InputStream alloStream; try { alloStream = MaryProperties.needStream(propertyName); } catch (FileNotFoundException e) { throw new MaryConfigurationException( "Cannot open allophone stream for property " + propertyName, e); } assert alloStream != null; return AllophoneSet.getAllophoneSet(alloStream, propertyValue); } public static String getMaryVersion() { String output = "Mary TTS server " + Version.specificationVersion() + " (impl. " + Version.implementationVersion() + ")"; return output; } public static String getDataTypes() { String output = ""; List<MaryDataType> allTypes = MaryDataType.getDataTypes(); for (MaryDataType t : allTypes) { output += t.name(); if (t.isInputType()) output += " INPUT"; if (t.isOutputType()) output += " OUTPUT"; output += System.getProperty("line.separator"); } return output; } public static String getLocales() { StringBuilder out = new StringBuilder(); for (LanguageConfig conf : MaryConfig.getLanguageConfigs()) { for (Locale locale : conf.getLocales()) { out.append(locale).append('\n'); } } return out.toString(); } public static String getVoices() { String output = ""; Collection<Voice> voices = Voice.getAvailableVoices(); for (Iterator<Voice> it = voices.iterator(); it.hasNext(); ) { Voice v = (Voice) it.next(); if (v instanceof InterpolatingVoice) { // do not list interpolating voice } else if (v instanceof UnitSelectionVoice) { output += v.getName() + " " + v.getLocale() + " " + v.gender().toString() + " " + "unitselection" + " " + ((UnitSelectionVoice) v).getDomain() + System.getProperty("line.separator"); } else if (v instanceof HMMVoice) { output += v.getName() + " " + v.getLocale() + " " + v.gender().toString() + " " + "hmm" + System.getProperty("line.separator"); } else { output += v.getName() + " " + v.getLocale() + " " + v.gender().toString() + " " + "other" + System.getProperty("line.separator"); } } return output; } public static String getDefaultVoiceName() { String defaultVoiceName = ""; String allVoices = getVoices(); if (allVoices != null && allVoices.length() > 0) { StringTokenizer tt = new StringTokenizer(allVoices, System.getProperty("line.separator")); if (tt.hasMoreTokens()) { defaultVoiceName = tt.nextToken(); StringTokenizer tt2 = new StringTokenizer(defaultVoiceName, " "); if (tt2.hasMoreTokens()) defaultVoiceName = tt2.nextToken(); } } return defaultVoiceName; } public static String getExampleText(String datatype, Locale locale) { MaryDataType type = MaryDataType.get(datatype); String exampleText = type.exampleText(locale); if (exampleText != null) return exampleText.trim() + System.getProperty("line.separator"); return ""; } public static Vector<String> getDefaultVoiceExampleTexts() { String defaultVoiceName = getDefaultVoiceName(); Vector<String> defaultVoiceExampleTexts = null; defaultVoiceExampleTexts = StringUtils.processVoiceExampleText(getVoiceExampleText(defaultVoiceName)); if (defaultVoiceExampleTexts == null) // Try for general domain { String str = getExampleText("TEXT", Voice.getVoice(defaultVoiceName).getLocale()); if (str != null && str.length() > 0) { defaultVoiceExampleTexts = new Vector<String>(); defaultVoiceExampleTexts.add(str); } } return defaultVoiceExampleTexts; } public static String getVoiceExampleText(String voiceName) { Voice v = Voice.getVoice(voiceName); if (v instanceof marytts.unitselection.UnitSelectionVoice) return ((marytts.unitselection.UnitSelectionVoice) v).getExampleText(); return ""; } /** * For the voice with the given name, return the list of vocalizations supported by this voice, * one vocalization per line. These values can be used in the "name" attribute of the vocalization * tag. * * @param voiceName * @return the list of vocalizations, or the empty string if the voice does not support * vocalizations. */ public static String getVocalizations(String voiceName) { Voice v = Voice.getVoice(voiceName); if (v == null || !v.hasVocalizationSupport()) { return ""; } VocalizationSynthesizer vs = v.getVocalizationSynthesizer(); assert vs != null; String[] vocalizations = vs.listAvailableVocalizations(); assert vocalizations != null; return StringUtils.toString(vocalizations); } public static String getDefaultAudioEffects() { // Marc, 8.1.09: Simplified format // name params StringBuilder sb = new StringBuilder(); for (AudioEffect effect : AudioEffects.getEffects()) { sb.append(effect.getName()).append(" ").append(effect.getExampleParameters()).append("\n"); } return sb.toString(); } public static String getAudioEffectDefaultParam(String effectName) { AudioEffect effect = AudioEffects.getEffect(effectName); if (effect == null) { return ""; } return effect.getExampleParameters().trim(); } public static String getFullAudioEffect(String effectName, String currentEffectParams) { AudioEffect effect = AudioEffects.getEffect(effectName); if (effect == null) { return ""; } effect.setParams(currentEffectParams); return effect.getFullEffectAsString(); } public static String getAudioEffectHelpText(String effectName) { AudioEffect effect = AudioEffects.getEffect(effectName); if (effect == null) { return ""; } return effect.getHelpText().trim(); } public static String isHmmAudioEffect(String effectName) { AudioEffect effect = AudioEffects.getEffect(effectName); if (effect == null) { return ""; } return effect.isHMMEffect() ? "yes" : "no"; } }