/**
   * 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);
  }
Beispiel #2
0
 /**
  * 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;
 }
Beispiel #3
0
 /**
  * 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;
 }
Beispiel #5
0
 /**
  * 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;
 }
Beispiel #6
0
/** @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";
  }
}